home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-19 / gpt32src.zip / COMMAND.C < prev    next >
C/C++ Source or Header  |  1992-03-25  |  92KB  |  3,349 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: command.c,v 3.26 92/03/24 22:34:17 woo Exp Locker: woo $";
  3. #endif
  4.  
  5. /* GNUPLOT - command.c */
  6. /*
  7.  * Copyright (C) 1986, 1987, 1990, 1991, 1992   Thomas Williams, Colin Kelley
  8.  *
  9.  * Permission to use, copy, and distribute this software and its
  10.  * documentation for any purpose with or without fee is hereby granted, 
  11.  * provided that the above copyright notice appear in all copies and 
  12.  * that both that copyright notice and this permission notice appear 
  13.  * in supporting documentation.
  14.  *
  15.  * Permission to modify the software is granted, but not the right to
  16.  * distribute the modified code.  Modifications are to be distributed 
  17.  * as patches to released version.
  18.  *  
  19.  * This software is provided "as is" without express or implied warranty.
  20.  * 
  21.  *
  22.  * AUTHORS
  23.  * 
  24.  *   Original Software:
  25.  *     Thomas Williams,  Colin Kelley.
  26.  * 
  27.  *   Gnuplot 2.0 additions:
  28.  *       Russell Lang, Dave Kotz, John Campbell.
  29.  *
  30.  *   Gnuplot 3.0 additions:
  31.  *       Gershon Elber and many others.
  32.  * 
  33.  * Send your comments or suggestions to 
  34.  *  info-gnuplot@ames.arc.nasa.gov.
  35.  * This is a mailing list; to join it send a note to 
  36.  *  info-gnuplot-request@ames.arc.nasa.gov.  
  37.  * Send bug reports to
  38.  *  bug-gnuplot@ames.arc.nasa.gov.
  39.  */
  40.  
  41. #include <stdio.h>
  42. #include <math.h>
  43.  
  44. #ifdef AMIGA_AC_5
  45. #include <time.h>
  46. void sleep();        /* defined later */
  47. #endif
  48.  
  49. #ifdef MSDOS
  50. #include <process.h>
  51.  
  52. #ifdef __ZTC__
  53. #define P_WAIT 0
  54. #include <time.h>    /* usleep() */
  55. #else
  56.  
  57. #ifdef __TURBOC__
  58. #include <dos.h>    /* sleep() */
  59. #include <conio.h>
  60. extern unsigned _stklen = 16394;    /* increase stack size */
  61.  
  62. #else    /* must be MSC */
  63. #include <time.h>    /* kludge to provide sleep() */
  64. void sleep();        /* defined later */
  65. #endif /* TURBOC */
  66. #endif /* ZTC */
  67.  
  68. #endif /* MSDOS */
  69.  
  70. #ifdef AMIGA_LC_5_1
  71. #include <proto/dos.h>
  72. void sleep();
  73. #endif    /* AMIGA_LC_5_1 */
  74.  
  75. #include "plot.h"
  76. #include "setshow.h"
  77. #include "help.h"
  78.  
  79. #ifndef STDOUT
  80. #define STDOUT 1
  81. #endif
  82.  
  83. #ifndef HELPFILE
  84. #ifdef AMIGA_LC_5_1
  85. #define HELPFILE "S:gnuplot.gih"
  86. #else
  87. #define HELPFILE "docs/gnuplot.gih" /* changed by makefile */
  88. #endif /* AMIGA_LC_5_1 */
  89. #endif /* HELPFILE */
  90.  
  91. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  92.  
  93. /*
  94.  * instead of <strings.h>
  95.  */
  96.  
  97. extern char *gets(),*getenv();
  98. extern char *strcpy(),*strncpy(),*strcat();
  99. extern int strlen(), strcmp();
  100.  
  101. /*
  102.  * Only reference to contours library.
  103.  */
  104. extern struct gnuplot_contours *contour();
  105.  
  106. #if defined(unix) && !defined(hpux)
  107. #ifdef GETCWD
  108. extern char *getcwd();    /* some Unix's use getcwd */
  109. #else
  110. extern char *getwd();    /* most Unix's use getwd */
  111. #endif
  112. #else
  113. extern char *getcwd();    /* Turbo C, MSC and VMS use getcwd */
  114. #endif
  115.  
  116. #ifdef vms
  117. int vms_vkid; /* Virtual keyboard id */
  118. #endif
  119.  
  120. #ifdef unix
  121. extern FILE *popen();
  122. static BOOLEAN pipe_open=FALSE;
  123. #endif
  124.  
  125. extern int chdir();
  126.  
  127. extern double magnitude(),angle(),real(),imag();
  128. extern struct value *const_express(), *pop(), *complex();
  129. extern struct at_type *temp_at(), *perm_at();
  130. extern struct udft_entry *add_udf();
  131. extern struct udvt_entry *add_udv();
  132. extern void squash_spaces();
  133. extern void lower_case();
  134.  
  135. /* local functions */
  136. static enum coord_type adjustlog();
  137.  
  138. extern BOOLEAN interactive;    /* from plot.c */
  139.  
  140. /* input data, parsing variables */
  141. struct lexical_unit token[MAX_TOKENS];
  142. char input_line[MAX_LINE_LEN+1] = "";
  143. int num_tokens, c_token;
  144. int inline_num = 0;            /* input line number */
  145.  
  146. char c_dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1];    /* current dummy vars */
  147.  
  148. /* the curves/surfaces of the plot */
  149. struct curve_points *first_plot = NULL;
  150. struct surface_points *first_3dplot = NULL;
  151. static struct udft_entry plot_func;
  152. struct udft_entry *dummy_func;
  153.  
  154. /* support for replot command */
  155. char replot_line[MAX_LINE_LEN+1] = "";
  156. static int plot_token;                    /* start of 'plot' command */
  157.  
  158. /* If last plot was a 3d one. */
  159. BOOLEAN is_3d_plot = FALSE;
  160.  
  161. com_line()
  162. {
  163.     read_line(PROMPT);
  164.  
  165.     /* So we can flag any new output: if false at time of error, */
  166.     /* we reprint the command line before printing caret. */
  167.     /* TRUE for interactive terminals, since the command line is typed. */
  168.     /* FALSE for non-terminal stdin, so command line is printed anyway. */
  169.     /* (DFK 11/89) */
  170.     screen_ok = interactive; 
  171.  
  172.     do_line();
  173. }
  174.  
  175.  
  176. do_line()      /* also used in load_file */
  177. {
  178.     if (is_system(input_line[0])) {
  179.         do_system();
  180.         (void) fputs("!\n",stderr);
  181.         return;
  182.     }
  183.     num_tokens = scanner(input_line);
  184.     c_token = 0;
  185.     while(c_token < num_tokens) {
  186.         command();
  187.         if (c_token < num_tokens)    /* something after command */
  188.             if (equals(c_token,";"))
  189.                 c_token++;
  190.             else
  191.                     int_error("';' expected",c_token);
  192.     }
  193. }
  194.  
  195.  
  196.  
  197. command()
  198. {
  199.     int i;
  200.     char sv_file[MAX_LINE_LEN+1];
  201.     /* string holding name of save or load file */
  202.  
  203.     for (i = 0; i < MAX_NUM_VAR; i++)
  204.         c_dummy_var[i][0] = '\0';        /* no dummy variables */
  205.  
  206.     if (is_definition(c_token))
  207.         define();
  208.     else if (almost_equals(c_token,"h$elp") || equals(c_token,"?")) {
  209.         c_token++;
  210.         do_help();
  211.     }
  212.     else if (almost_equals(c_token,"test")) {
  213.         c_token++;
  214.         test_term();
  215.     }
  216.     else if (almost_equals(c_token,"pa$use")) {
  217.         struct value a;
  218.         int stime, text=0;
  219.         char buf[MAX_LINE_LEN+1];
  220.  
  221.         c_token++;
  222.         stime = (int )real(const_express(&a));
  223.         if (!(END_OF_COMMAND)) {
  224.             if (!isstring(c_token))
  225.                 int_error("expecting string",c_token);
  226.             else {
  227.                 quotel_str(buf,c_token);
  228.                 (void) fprintf (stderr, "%s",buf);
  229.                 text = 1;
  230.             }
  231.         }
  232.         if (stime < 0) (void) fgets (buf,MAX_LINE_LEN,stdin);  
  233.                         /* Hold until CR hit. */
  234. #ifdef __ZTC__
  235.         if (stime > 0) usleep((unsigned long) stime);
  236. #else
  237.         if (stime > 0) sleep((unsigned int) stime);
  238. #endif
  239.         if (text != 0 && stime >= 0) (void) fprintf (stderr,"\n");
  240.         c_token++;
  241.         screen_ok = FALSE;
  242.     }
  243.     else if (almost_equals(c_token,"pr$int")) {
  244.         struct value a;
  245.  
  246.         c_token++;
  247.         (void) const_express(&a);
  248.         (void) putc('\t',stderr);
  249.         disp_value(stderr,&a);
  250.         (void) putc('\n',stderr);
  251.         screen_ok = FALSE;
  252.     }
  253.     else if (almost_equals(c_token,"p$lot")) {
  254.         plot_token = c_token++;
  255.         plotrequest();
  256.     }
  257.     else if (almost_equals(c_token,"sp$lot")) {
  258.         plot_token = c_token++;
  259.         plot3drequest();
  260.     }
  261.     else if (almost_equals(c_token,"rep$lot")) {
  262.         if (replot_line[0] == '\0') 
  263.             int_error("no previous plot",c_token);
  264.         c_token++;
  265.         replotrequest();
  266.     }
  267.     else if (almost_equals(c_token,"se$t"))
  268.         set_command();
  269.     else if (almost_equals(c_token,"sh$ow"))
  270.         show_command();
  271.     else if (almost_equals(c_token,"cl$ear")) {
  272.         if (!term_init) {
  273.             (*term_tbl[term].init)();
  274.             term_init = TRUE;
  275.         }
  276.         (*term_tbl[term].graphics)();
  277.         (*term_tbl[term].text)();
  278.         (void) fflush(outfile);
  279.         screen_ok = FALSE;
  280.         c_token++;
  281.     }
  282.     else if (almost_equals(c_token,"she$ll")) {
  283.         do_shell();
  284.         screen_ok = FALSE;
  285.         c_token++;
  286.     }
  287.     else if (almost_equals(c_token,"sa$ve")) {
  288.         if (almost_equals(++c_token,"f$unctions")) {
  289.             if (!isstring(++c_token))
  290.                 int_error("expecting filename",c_token);
  291.             else {
  292.                 quote_str(sv_file,c_token);
  293.                 save_functions(fopen(sv_file,"w"));
  294.             }
  295.         }
  296.         else if (almost_equals(c_token,"v$ariables")) {
  297.             if (!isstring(++c_token))
  298.                 int_error("expecting filename",c_token);
  299.             else {
  300.                 quote_str(sv_file,c_token);
  301.                 save_variables(fopen(sv_file,"w"));
  302.             }
  303.         }
  304.         else if (almost_equals(c_token,"s$et")) {
  305.             if (!isstring(++c_token))
  306.                 int_error("expecting filename",c_token);
  307.             else {
  308.                 quote_str(sv_file,c_token);
  309.                 save_set(fopen(sv_file,"w"));
  310.             }
  311.         }
  312.         else if (isstring(c_token)) {
  313.             quote_str(sv_file,c_token);
  314.             save_all(fopen(sv_file,"w"));
  315.         }
  316.         else {
  317.             int_error(
  318.         "filename or keyword 'functions', 'variables', or 'set' expected",
  319.                     c_token);
  320.         }
  321.         c_token++;
  322.     }
  323.     else if (almost_equals(c_token,"l$oad")) {
  324.         if (!isstring(++c_token))
  325.             int_error("expecting filename",c_token);
  326.         else {
  327.             quote_str(sv_file,c_token);
  328.             load_file(fopen(sv_file,"r"), sv_file);    
  329.         /* input_line[] and token[] now destroyed! */
  330.             c_token = num_tokens = 0;
  331.         }
  332.     }
  333.     else if (almost_equals(c_token,"cd")) {
  334.         if (!isstring(++c_token))
  335.             int_error("expecting directory name",c_token);
  336.         else {
  337.             quotel_str(sv_file,c_token);
  338.             if (chdir(sv_file)) {
  339.               int_error("Can't change to this directory",c_token);
  340.             }
  341.         c_token++;
  342.         }
  343.     }
  344.     else if (almost_equals(c_token,"pwd")) {
  345. #if defined(unix) && !defined(hpux)
  346. #ifdef GETCWD
  347.       (void) getcwd(sv_file,MAX_ID_LEN); /* some Unix's use getcwd */
  348. #else
  349.       (void) getwd(sv_file); /* most Unix's use getwd */
  350. #endif
  351. #else
  352. /* Turbo C and VMS have getcwd() */
  353.       (void) getcwd(sv_file,MAX_ID_LEN);
  354. #endif
  355.       fprintf(stderr,"%s\n", sv_file);
  356.       c_token++;
  357.     }
  358.     else if (almost_equals(c_token,"ex$it") ||
  359.             almost_equals(c_token,"q$uit")) {
  360.         done(IO_SUCCESS);
  361.     }
  362.     else if (!equals(c_token,";")) {        /* null statement */
  363.         int_error("invalid command",c_token);
  364.     }
  365. }
  366.  
  367. replotrequest()
  368. {
  369. char str[MAX_LINE_LEN+1];
  370.         if(equals(c_token,"["))
  371.             int_error("cannot set range with replot",c_token);
  372.         if (!END_OF_COMMAND) {
  373.             capture(str,c_token,num_tokens-1);
  374.             if ( (strlen(str) + strlen(replot_line)) <= MAX_LINE_LEN-1) {
  375.                 (void) strcat(replot_line,",");
  376.                 (void) strcat(replot_line,str); 
  377.             } else {
  378.                 int_error("plot line too long with replot arguments",c_token);
  379.             }
  380.         }
  381.         (void) strcpy(input_line,replot_line);
  382.         screen_ok = FALSE;
  383.         num_tokens = scanner(input_line);
  384.         c_token = 1;                    /* skip the 'plot' part */
  385.         is_3d_plot ? plot3drequest() : plotrequest();
  386. }
  387.  
  388.  
  389. plotrequest()
  390. /*
  391.    In the parametric case we can say 
  392.       plot [a= -4:4] [-2:2] [-1:1] sin(a),a**2
  393.    while in the non-parametric case we would say only
  394.       plot [b= -2:2] [-1:1] sin(b)
  395. */
  396. {
  397.     BOOLEAN changed;
  398.     int dummy_token = -1;
  399.  
  400.     is_3d_plot = FALSE;
  401.  
  402.     if (parametric && strcmp(dummy_var[0], "u") == 0)
  403.     strcpy (dummy_var[0], "t");
  404.  
  405.     autoscale_lt = autoscale_t;
  406.     autoscale_lx = autoscale_x;
  407.     autoscale_ly = autoscale_y;
  408.  
  409.     if (!term)                    /* unknown */
  410.         int_error("use 'set term' to set terminal type first",c_token);
  411.  
  412.     if (equals(c_token,"[")) {
  413.         c_token++;
  414.         if (isletter(c_token)) {
  415.             if (equals(c_token+1,"=")) {
  416.                dummy_token = c_token;
  417.                c_token += 2;
  418.             } else {
  419.                /* oops; probably an expression with a variable. */
  420.                /* Parse it as an xmin expression. */
  421.                /* used to be: int_error("'=' expected",c_token); */
  422.             }
  423.         }
  424.         changed = parametric ? load_range(&tmin,&tmax):load_range(&xmin,&xmax);
  425.         if (!equals(c_token,"]"))
  426.             int_error("']' expected",c_token);
  427.         c_token++;
  428.         if (changed) {
  429.             if (parametric)
  430.                 autoscale_lt = FALSE;
  431.             else
  432.                 autoscale_lx = FALSE;
  433.         }
  434.     }
  435.  
  436.     if (parametric && equals(c_token,"[")) { /* set optional x ranges */
  437.         c_token++;
  438.         changed = load_range(&xmin,&xmax);
  439.         if (!equals(c_token,"]"))
  440.             int_error("']' expected",c_token);
  441.         c_token++;
  442.         if (changed)
  443.           autoscale_lx = FALSE;
  444.     }
  445.  
  446.     if (equals(c_token,"[")) { /* set optional y ranges */
  447.         c_token++;
  448.         changed = load_range(&ymin,&ymax);
  449.         if (!equals(c_token,"]"))
  450.             int_error("']' expected",c_token);
  451.         c_token++;
  452.         if (changed)
  453.           autoscale_ly = FALSE;
  454.     }
  455.  
  456.      /* use the default dummy variable unless changed */
  457.     if (dummy_token >= 0)
  458.       copy_str(c_dummy_var[0],dummy_token);
  459.     else
  460.       (void) strcpy(c_dummy_var[0],dummy_var[0]);
  461.  
  462.     eval_plots();
  463. }
  464.  
  465. plot3drequest()
  466. /*
  467.    in the parametric case we would say
  468.       splot [u= -Pi:Pi] [v= 0:2*Pi] [-1:1] [-1:1] [-1:1] sin(v)*cos(u),sin(v)*cos(u),sin(u)
  469.    in the non-parametric case we would say only
  470.       splot [x= -2:2] [y= -5:5] sin(x)*cos(y)
  471.  
  472. */
  473. {
  474.     BOOLEAN changed;
  475.     int dummy_token0 = -1,
  476.     dummy_token1 = -1;
  477.  
  478.     is_3d_plot = TRUE;
  479.  
  480.     if (parametric && strcmp(dummy_var[0], "t") == 0) {
  481.         strcpy (dummy_var[0], "u");
  482.         strcpy (dummy_var[1], "v");
  483.     }
  484.  
  485.     autoscale_lx = autoscale_x;
  486.     autoscale_ly = autoscale_y;
  487.     autoscale_lz = autoscale_z;
  488.  
  489.     if (!term)                    /* unknown */
  490.         int_error("use 'set term' to set terminal type first",c_token);
  491.  
  492.     if (equals(c_token,"[")) {
  493.         c_token++;
  494.         if (isletter(c_token)) {
  495.             if (equals(c_token+1,"=")) {
  496.                dummy_token0 = c_token;
  497.                c_token += 2;
  498.             } else {
  499.                /* oops; probably an expression with a variable. */
  500.                /* Parse it as an xmin expression. */
  501.                /* used to be: int_error("'=' expected",c_token); */
  502.             }
  503.         }
  504.         changed = parametric ? load_range(&umin,&umax):load_range(&xmin,&xmax);
  505.         if (!equals(c_token,"]"))
  506.             int_error("']' expected",c_token);
  507.         c_token++;
  508.         if (changed && !parametric) {
  509.             autoscale_lx = FALSE;
  510.         }
  511.     }
  512.  
  513.     if (equals(c_token,"[")) {
  514.         c_token++;
  515.         if (isletter(c_token)) {
  516.             if (equals(c_token+1,"=")) {
  517.                dummy_token1 = c_token;
  518.                c_token += 2;
  519.             } else {
  520.                /* oops; probably an expression with a variable. */
  521.                /* Parse it as an xmin expression. */
  522.                /* used to be: int_error("'=' expected",c_token); */
  523.             }
  524.         }
  525.         changed = parametric ? load_range(&vmin,&vmax):load_range(&ymin,&ymax);
  526.         if (!equals(c_token,"]"))
  527.             int_error("']' expected",c_token);
  528.         c_token++;
  529.         if (changed && !parametric) {
  530.             autoscale_ly = FALSE;
  531.         }
  532.     }
  533.  
  534.     if (equals(c_token,"[")) { /* set optional x ranges */
  535.         c_token++;
  536.         changed = load_range(&xmin,&xmax);
  537.         if (!equals(c_token,"]"))
  538.             int_error("']' expected",c_token);
  539.         c_token++;
  540.         if (changed)
  541.           autoscale_lx = FALSE;
  542.     }
  543.  
  544.     if (equals(c_token,"[")) { /* set optional y ranges */
  545.         c_token++;
  546.         changed = load_range(&ymin,&ymax);
  547.         if (!equals(c_token,"]"))
  548.             int_error("']' expected",c_token);
  549.         c_token++;
  550.         if (changed)
  551.           autoscale_ly = FALSE;
  552.     }
  553.  
  554.     if (equals(c_token,"[")) { /* set optional z ranges */
  555.         c_token++;
  556.         changed = load_range(&zmin,&zmax);
  557.         if (!equals(c_token,"]"))
  558.             int_error("']' expected",c_token);
  559.         c_token++;
  560.         if (changed)
  561.           autoscale_lz = FALSE;
  562.     }
  563.  
  564.      /* use the default dummy variable unless changed */
  565.     if (dummy_token0 >= 0)
  566.       copy_str(c_dummy_var[0],dummy_token0);
  567.     else
  568.       (void) strcpy(c_dummy_var[0],dummy_var[0]);
  569.  
  570.     if (dummy_token1 >= 0)
  571.       copy_str(c_dummy_var[1],dummy_token1);
  572.     else
  573.       (void) strcpy(c_dummy_var[1],dummy_var[1]);
  574.  
  575.     eval_3dplots();
  576. }
  577.  
  578.  
  579. define()
  580. {
  581. register int start_token;  /* the 1st token in the function definition */
  582. register struct udvt_entry *udv;
  583. register struct udft_entry *udf;
  584.  
  585.     if (equals(c_token+1,"(")) {
  586.         /* function ! */
  587.         start_token = c_token;
  588.         copy_str(c_dummy_var[0], c_token + 2);
  589.         if(equals(c_token+3,",")) {
  590.             copy_str(c_dummy_var[1], c_token + 4);
  591.             c_token += 2;  /* skip the  , dummy2 */
  592.         }
  593.         c_token += 5; /* skip (, dummy, ) and = */
  594.         if (END_OF_COMMAND)
  595.             int_error("function definition expected",c_token);
  596.         udf = dummy_func = add_udf(start_token);
  597.         if (udf->at)                /* already a dynamic a.t. there */
  598.             free((char *)udf->at);    /* so free it first */
  599.         if ((udf->at = perm_at()) == (struct at_type *)NULL)
  600.             int_error("not enough memory for function",start_token);
  601.         m_capture(&(udf->definition),start_token,c_token-1);
  602.     }
  603.     else {
  604.         /* variable ! */
  605.         start_token = c_token;
  606.         c_token +=2;
  607.         udv = add_udv(start_token);
  608.         (void) const_express(&(udv->udv_value));
  609.         udv->udv_undef = FALSE;
  610.     }
  611. }
  612.  
  613.  
  614. get_data(this_plot)
  615. struct curve_points *this_plot;
  616. {
  617. register int i, l_num, datum;
  618. register FILE *fp;
  619. float x, y;
  620. float ylow, yhigh;            /* for error bars */
  621. float temp;
  622. BOOLEAN yfirst;
  623. char format[MAX_LINE_LEN+1], data_file[MAX_LINE_LEN+1], line[MAX_LINE_LEN+1];
  624. char *float_format = "%f", *float_skip = "%*f";
  625. int xcol = 1, ycol = 2, yemin = 3, yemax = 4;
  626. struct value colvalue;
  627. #ifdef AMIGA_LC_5_1
  628. int num_perc_ast;
  629. char *start_search;
  630. #endif /* AMIGA_LC_5_1 */
  631.  
  632.     quote_str(data_file, c_token);
  633.     this_plot->plot_type = DATA;
  634.     if( parametric)
  635.         int_error("Parametric data files not yet implemented",NO_CARET);
  636. #ifdef unix
  637.     if ( *data_file == '<' ) {
  638.           if ((fp = popen(data_file+1,"r")) == (FILE *)NULL)
  639.             os_error("cannot create pipe; output not changed",c_token);
  640.         else
  641.             pipe_open = TRUE;
  642.     } else
  643. #endif
  644.     if ((fp = fopen(data_file, "r")) == (FILE *)NULL)
  645.         os_error("can't open data file", c_token);
  646.  
  647.     format[0] = '\0';
  648.     yfirst = FALSE;
  649.     c_token++;    /* skip data file name */
  650.     if (almost_equals(c_token,"u$sing")) {
  651.         c_token++;      /* skip "using" */
  652.         if (!END_OF_COMMAND && !isstring(c_token)) {
  653.             struct value a;
  654.             ycol = (int)magnitude(const_express(&a));
  655.             xcol = ycol;
  656.             if (equals(c_token,":")) {
  657.                 c_token++;      /* skip ":" */
  658.                 ycol = (int)magnitude(const_express(&a));
  659.                 if (equals(c_token,":")) {
  660.                     c_token++;      /* skip ":" */
  661.                     yemin = (int)magnitude(const_express(&a));
  662.                     if (equals(c_token,":")) {
  663.                         c_token++;      /* skip ":" */
  664.                         yemax = (int)magnitude(const_express(&a));
  665.                     }
  666.                     else
  667.                             yemax = -1;
  668.                 }
  669.                 else {
  670.                         yemin = -1;
  671.                         yemax = -1;
  672.                 }
  673.             }
  674.             else {
  675.                     yemin = -1;
  676.                     yemax = -1;
  677.             }
  678.             if (xcol > ycol) yfirst = TRUE;
  679.         }
  680.         if (!END_OF_COMMAND && isstring(c_token)) {
  681.             quotel_str(format, c_token);
  682.             c_token++;    /* skip format */
  683.         }
  684.     }
  685.     if (strlen(format) == 0) {
  686.         for(i = 1; i <= ((xcol > ycol) ? xcol : ycol); i++)
  687.             if ((i == xcol) || (i == ycol))
  688.                 (void) strcat(format,float_format);
  689.             else
  690.                 (void) strcat(format,float_skip);
  691.  
  692.         if (yemin > 0) {
  693.             /* We have error bars - handle them. */
  694.             yemin -= (xcol > ycol) ? xcol : ycol;
  695.             yemax -= (xcol > ycol) ? xcol : ycol;
  696.             if (yemin > yemax && yemax > 0) {
  697.                 i = yemin;
  698.                 yemin = yemax;
  699.                 yemax = i;
  700.             }
  701.  
  702.             if (yemin == yemax)
  703.                 int_error("Two error bar columns are the same",
  704.                       NO_CARET);
  705.  
  706.             if (yemin <= 0)
  707.                 int_error("Error bar columns must follow data columns",
  708.                       NO_CARET);
  709.  
  710.             for (i = 1; i < yemin; i++)
  711.                 (void) strcat(format,float_skip);
  712.             (void) strcat(format,float_format);
  713.  
  714.             if (yemax > 0) {
  715.                 for (i = 1; i < yemax - yemin; i++)
  716.                     (void) strcat(format,float_skip);
  717.                 (void) strcat(format,float_format);
  718.             }
  719.         }
  720.     }
  721.  
  722.     l_num = 0;
  723.      datum = 0;
  724.     i = 0;
  725. #ifdef AMIGA_LC_5_1
  726.     num_perc_ast = 0;
  727.     start_search = format;
  728.     while (*start_search != '\0') {
  729.         if (start_search[0] == '%')
  730.             if (start_search[1] == '*') num_perc_ast++;
  731.         start_search++;
  732.     }
  733. #endif /* AMIGA_LC_5_1 */
  734.     while ( fgets(line, MAX_LINE_LEN, fp) != (char *)NULL ) {
  735.         l_num++;
  736.         if (is_comment(line[0]))
  737.             continue;        /* ignore comments */
  738.         if (i >= this_plot->p_max) {
  739.             /* overflow about to occur. Extend size of points[]
  740.             * array. We either double the size, or add 1000 points,
  741.             * whichever is a smaller increment. Note i=p_max.
  742.             */
  743.             cp_extend(this_plot, i + (i < 1000 ? i : 1000));
  744.         }
  745.         if (!line[1]) { /* is it blank line ? */
  746.             /* break in data, make next point undefined */
  747.             this_plot->points[i].type = UNDEFINED;
  748.             i++;
  749.             continue;
  750.         }
  751.  
  752. #ifdef AMIGA_LC_5_1
  753.         switch (sscanf(line, format, &x, &y, &ylow, &yhigh) -
  754.              num_perc_ast) {
  755. #else /* AMIGA_LC_5_1 */
  756.         switch (sscanf(line, format, &x, &y, &ylow, &yhigh)) {
  757. #endif /* AMIGA_LC_5_1 */
  758.             case 1: {        /* only one number on the line */
  759.                y = x;        /* assign that number to y */
  760.                x = datum;    /* and make the index into x */
  761.                /* no break; !!! */
  762.             }
  763.             case 2: {
  764.                if (yfirst) { /* exchange x and y */
  765.                   temp = y;
  766.                   y = x;
  767.                   x = temp;
  768.                }
  769.                datum++;
  770.  
  771.                /* ylow and yhigh are same as y */
  772.                store2d_point(this_plot, i++, x, y, y, y);
  773.                break;
  774.             }
  775.             case 3: {        /* x, y, ydelta */
  776.                if (yfirst) { /* exchange x and y */
  777.                   temp = y;
  778.                   y = x;
  779.                   x = temp;
  780.                }
  781.                datum++;
  782.  
  783.                /* ydelta is in the ylow variable */
  784.                store2d_point(this_plot, i++, x, y, y-ylow, y+ylow);
  785.                break;
  786.             }
  787.             case 4: {        /* x, y, ylow, yhigh */
  788.                if (yfirst) { /* exchange x and y */
  789.                   temp = y;
  790.                   y = x;
  791.                   x = temp;
  792.                }
  793.                datum++;
  794.  
  795.                store2d_point(this_plot, i++, x, y, ylow, yhigh);
  796.                break;
  797.             }
  798.             default: {
  799.                (void) sprintf(line, "bad data on line %d", l_num);
  800.                int_error(line,c_token);
  801.             }
  802.         }
  803.     }
  804.     this_plot->p_count = i;
  805.     cp_extend(this_plot, i);    /* shrink to fit */
  806.  
  807. #ifdef unix
  808.     if ( pipe_open ) {
  809.         (void) pclose(fp);
  810.         pipe_open = FALSE;
  811.     } else
  812. #endif
  813.     (void) fclose(fp);
  814. }
  815.  
  816. /* called by get_data for each point */
  817. store2d_point(this_plot, i, x, y, ylow, yhigh)
  818. struct curve_points *this_plot;
  819. int i;                    /* point number */
  820. #ifdef AMIGA_LC_5_1
  821. double x, y;
  822. double ylow, yhigh;
  823. #else
  824. float x, y;
  825. float ylow, yhigh;
  826. #endif
  827. {
  828.     struct coordinate *cp = &(this_plot->points[i]);
  829.  
  830.     /* the easy part: */
  831.     cp->type = INRANGE;
  832.     cp->x = x;
  833.     cp->y = y;
  834.     cp->ylow = ylow;
  835.     cp->yhigh = yhigh;
  836.     
  837.     /* Adjust for log scale. */
  838.     if (log_x)
  839.      cp->type = adjustlog(cp->type, &(cp->x));
  840.     if (log_y) {
  841.        cp->type = adjustlog(cp->type, &(cp->y));
  842.        /* Note ylow,yhigh can't affect cp->type. */
  843.        (void)     adjustlog(cp->type, &(cp->ylow));
  844.        (void)     adjustlog(cp->type, &(cp->yhigh));
  845.     }
  846.  
  847.     /* Now adjust the xrange, or declare the point out of range */
  848.     /* The yrange is handled later, once we know whether to 
  849.     * include ylow, yhigh in the calculation. See adjust_yrange()
  850.     */
  851.     if (cp->type == INRANGE)
  852.      if (autoscale_lx || inrange(x,xmin,xmax)) {
  853.         if (autoscale_lx) {
  854.             if (x < xmin) xmin = x;
  855.             if (x > xmax) xmax = x;
  856.         }
  857.      } else {
  858.         cp->type = OUTRANGE;
  859.      }
  860. }
  861.  
  862. /* Adjust for log scale:
  863.  * take the log of the second parameter, in place, if possible. 
  864.  * If not possible, return new type for point; if possible, then 
  865.  * return old type for point.
  866.  */
  867. static enum coord_type
  868. adjustlog(type, val)
  869.     enum coord_type type;
  870.     coordval *val;
  871. {
  872.     if (*val < 0.0) {
  873.        return(UNDEFINED);
  874.     } else if (*val == 0.0) {
  875.        *val = -VERYLARGE;
  876.        return(OUTRANGE);
  877.     } else {
  878.        *val = log10(*val);
  879.        return(type);
  880.     }
  881. }
  882.  
  883.  
  884. /* now adjust the yrange, or declare the point out of range */
  885. /* this does all points in a curve */
  886. adjust_yrange(curve)
  887.     struct curve_points *curve;
  888. {
  889.     BOOLEAN ebars = (curve->plot_style == ERRORBARS);
  890.     int npoints = curve->p_count; /* number of points */
  891.     coordval y, ylow, yhigh;    /* one point value */
  892.     struct coordinate *cp;    /* one coordinate */
  893.     int i;                /* index into points */
  894.  
  895.     for (i = 0; i < npoints; i++) {
  896.        cp = &(curve->points[i]);
  897.        if (cp->type == INRANGE) {
  898.           y = log_y ? pow(10.0,cp->y) : cp->y;
  899.           if ((autoscale_ly ||
  900.                inrange(y, ymin, ymax) ||
  901.                polar)) {
  902.              if (autoscale_ly) {
  903.                 if (y < ymin) ymin = y;
  904.                 if (y > ymax) ymax = y;
  905.                 if (ebars) {
  906.                     ylow =  log_y ? pow(10.0,cp->ylow)  : cp->ylow;
  907.                     yhigh = log_y ? pow(10.0,cp->yhigh) : cp->yhigh;
  908.                     if (ylow < ymin) ymin = ylow;
  909.                     if (ylow > ymax) ymax = ylow;
  910.                     if (yhigh < ymin) ymin = yhigh;
  911.                     if (yhigh > ymax) ymax = yhigh;
  912.                 }
  913.              }
  914.           } else {
  915.              cp->type = OUTRANGE;
  916.           }
  917.        }
  918.     }
  919. }
  920.  
  921.  
  922. get_3ddata(this_plot)
  923. struct surface_points *this_plot;
  924. {
  925. register int i, j, l_num, xdatum, ydatum;
  926. register FILE *fp;
  927. float x, y, z;
  928. BOOLEAN only_z = FALSE;
  929. char format[MAX_LINE_LEN+1], data_file[MAX_LINE_LEN+1], line[MAX_LINE_LEN+1];
  930. char *float_format = "%f", *float_skip = "%*f";
  931. int xcol = 1, ycol = 2, zcol = 3, pt_in_iso_crv = 0, maxcol;
  932. enum XYZ_order_type {XYZ, YXZ, ZXY, XZY, ZYX, YZX, XY, YX} xyz_order;
  933. struct iso_curve *this_iso;
  934. #ifdef AMIGA_LC_5_1
  935. int num_perc_ast;
  936. char *start_search;
  937. #endif /* AMIGA_LC_5_1 */
  938.         
  939.     quote_str(data_file, c_token);
  940.     this_plot->plot_type = DATA3D;
  941.     this_plot->has_grid_topology = TRUE;
  942. #ifdef unix
  943.     if ( *data_file == '<' ) {
  944.         if ((fp = popen(data_file+1,"r")) == (FILE *)NULL)
  945.             os_error("cannot create pipe; output not changed",c_token);
  946.           else
  947.             pipe_open = TRUE;
  948.     } else
  949. #endif
  950.     if ((fp = fopen(data_file, "r")) == (FILE *)NULL)
  951.         os_error("can't open data file", c_token);
  952.  
  953.     format[0] = '\0';
  954.     c_token++;    /* skip data file name */
  955.     if (almost_equals(c_token,"u$sing")) {
  956.         c_token++;      /* skip "using" */
  957.         if (!END_OF_COMMAND && !isstring(c_token)) {
  958.             struct value a;
  959.             zcol = (int)magnitude(const_express(&a));
  960.             only_z = TRUE;
  961.             if (equals(c_token,":")) {
  962.                 c_token++;    /* skip ":" */
  963.                 only_z = FALSE;
  964.                 ycol = zcol;
  965.                 zcol = (int)magnitude(const_express(&a));
  966.                 if (equals(c_token,":")) {
  967.                     c_token++;    /* skip ":" */
  968.                     xcol = ycol;
  969.                     ycol = zcol;
  970.                     zcol = (int)magnitude(const_express(&a));
  971.                 }
  972.                 else {
  973.                     if (mapping3d == MAP3D_CARTESIAN)
  974.                         int_error("Must specify 1 or 3 columns",c_token);
  975.                     xcol = ycol;
  976.                     ycol = zcol;
  977.                 }
  978.             }
  979.             if (!only_z)
  980.                 if ( (xcol == ycol) || (ycol == zcol) || (xcol == zcol))
  981.                     int_error("Columns must be distinct",c_token);
  982.         }
  983.         if (!END_OF_COMMAND && isstring(c_token)) {
  984.             quotel_str(format, c_token);
  985.             c_token++;    /* skip format */
  986.         }
  987.     }
  988.     else {
  989.         if ( only_z = !parametric )
  990.         zcol = 1;
  991.     }
  992.  
  993.     switch (mapping3d) {
  994.         case MAP3D_CARTESIAN:
  995.         maxcol = (xcol > ycol) ? xcol : ycol;
  996.         maxcol = (maxcol > zcol) ? maxcol : zcol;
  997.         if (!only_z) {    /* Determine ordering of input columns */
  998.              if (zcol == maxcol) {
  999.                  if (xcol < ycol)
  1000.                      xyz_order = XYZ;  /* scanf(x,y,z) */
  1001.                  else
  1002.                      xyz_order = YXZ;  /* scanf(y,x,z) */
  1003.              }
  1004.              else if (ycol == maxcol) {
  1005.                  if (xcol < zcol)
  1006.                      xyz_order = XZY;  /* scanf(x,z,y) */
  1007.                  else
  1008.                      xyz_order = ZXY;  /* scanf(z,x,y) */
  1009.              }
  1010.              else {
  1011.                  if (ycol < zcol)
  1012.                      xyz_order = YZX;  /* scanf(y,z,x) */
  1013.                  else
  1014.                      xyz_order = ZYX;  /* scanf(z,y,x) */
  1015.              }
  1016.         }
  1017.         if (strlen(format) == 0) {
  1018.             if (only_z) {
  1019.                 for(i = 1; i <= zcol; i++)
  1020.                     if (i == zcol)
  1021.                         (void) strcat(format,float_format);
  1022.                     else
  1023.                         (void) strcat(format,float_skip);
  1024.             }
  1025.             else {
  1026.                 for(i = 1; i <= maxcol; i++)
  1027.                     if ((i == xcol) || (i == ycol) || (i == zcol))
  1028.                         (void) strcat(format,float_format);
  1029.                     else
  1030.                         (void) strcat(format,float_skip);
  1031.             }
  1032.         }
  1033.             break;
  1034.         case MAP3D_SPHERICAL:
  1035.         case MAP3D_CYLINDRICAL:
  1036.         if (only_z)
  1037.             int_error("Two columns for spherical/cylindrical coords.",c_token);
  1038.         maxcol = (xcol > ycol) ? xcol : ycol;
  1039.         xyz_order = (xcol < ycol) ? XY : YX;
  1040.         for(i = 1; i <= maxcol; i++)
  1041.             if ((i == xcol) || (i == ycol))
  1042.                 (void) strcat(format,float_format);
  1043.             else
  1044.                 (void) strcat(format,float_skip);
  1045.     }
  1046. #ifdef AMIGA_LC_5_1
  1047.     num_perc_ast = 0;
  1048.     start_search = format;
  1049.     while (*start_search != '\0') {
  1050.         if (start_search[0] == '%')
  1051.             if (start_search[1] == '*') num_perc_ast++;
  1052.         start_search++;
  1053.     }
  1054. #endif /* AMIGA_LC_5_1 */
  1055.  
  1056.     l_num = 0;
  1057.     xdatum = 0;
  1058.     ydatum = 0;
  1059.     this_plot->num_iso_read = 0;
  1060.     this_plot->has_grid_topology = TRUE;
  1061.     if ( this_plot->iso_crvs != NULL ) {
  1062.         struct iso_curve *icrv, *icrvs = this_plot->iso_crvs;
  1063.  
  1064.         while ( icrvs ) {
  1065.         icrv = icrvs;
  1066.         icrvs = icrvs->next;
  1067.         iso_free( icrv );
  1068.         }
  1069.         this_plot->iso_crvs = NULL;
  1070.     }
  1071.     this_iso = iso_alloc( samples );
  1072.  
  1073.     while ( fgets(line, MAX_LINE_LEN, fp) != (char *)NULL ) {
  1074.         l_num++;
  1075.         if (is_comment(line[0]))
  1076.             continue;        /* ignore comments */
  1077.         if (!line[1]) {            /* is it blank line ? */
  1078.                 if (pt_in_iso_crv == 0) {
  1079.                     if (xdatum == 0)
  1080.                     continue;
  1081.                     pt_in_iso_crv = xdatum;
  1082.             }
  1083.  
  1084.             if (xdatum > 0) {
  1085.                 this_iso->p_count = xdatum;
  1086.                 this_iso->next = this_plot->iso_crvs;
  1087.                 this_plot->iso_crvs = this_iso;
  1088.                 this_plot->num_iso_read++;
  1089.  
  1090.                 if (xdatum != pt_in_iso_crv)
  1091.                     this_plot->has_grid_topology = FALSE;
  1092.  
  1093.                 this_iso = iso_alloc(pt_in_iso_crv);
  1094.                 xdatum = 0;
  1095.                 ydatum++;
  1096.             }
  1097.             continue;
  1098.         }
  1099.  
  1100.         if (xdatum >= this_iso->p_max)
  1101.         {
  1102.             /* overflow about to occur. Extend size of points[]
  1103.             * array. We either double the size, or add 1000 points,
  1104.             * whichever is a smaller increment. Note i=p_max.
  1105.             */
  1106.             iso_extend(this_iso,
  1107.                    xdatum + (xdatum < 1000 ? xdatum : 1000));
  1108.         }
  1109.  
  1110. #ifdef AMIGA_LC_5_1
  1111.         switch (sscanf(line, format, &x, &y, &z) - num_perc_ast) {
  1112. #else
  1113.         switch (sscanf(line, format, &x, &y, &z)) {
  1114. #endif
  1115.             case 3:         /* All parameter are specified. */
  1116.                if (!only_z) {
  1117.                 switch (xyz_order) {
  1118.                    case XYZ:    /* scanf(x,y,z) */
  1119.                     this_iso->points[xdatum].x = x;
  1120.                     this_iso->points[xdatum].y = y;
  1121.                     this_iso->points[xdatum].z = z;
  1122.                     break;
  1123.                    case XZY:    /* scanf(x,z,y) */
  1124.                     this_iso->points[xdatum].x = x;
  1125.                     this_iso->points[xdatum].y = z;
  1126.                     this_iso->points[xdatum].z = y;
  1127.                     break;
  1128.                    case YXZ:     /* scanf(y,x,z) */
  1129.                     this_iso->points[xdatum].x = y;
  1130.                     this_iso->points[xdatum].y = x;
  1131.                     this_iso->points[xdatum].z = z;
  1132.                     break;
  1133.                    case ZXY:    /* scanf(z,x,y) */
  1134.                     this_iso->points[xdatum].x = y;
  1135.                     this_iso->points[xdatum].y = z;
  1136.                     this_iso->points[xdatum].z = x;
  1137.                     break;
  1138.                    case YZX:    /* scanf(y,z,x) */
  1139.                     this_iso->points[xdatum].x = z;
  1140.                     this_iso->points[xdatum].y = x;
  1141.                     this_iso->points[xdatum].z = y;
  1142.                     break;
  1143.                    case ZYX:    /* scanf(z,y,x) */
  1144.                     this_iso->points[xdatum].x = z;
  1145.                     this_iso->points[xdatum].y = y;
  1146.                     this_iso->points[xdatum].z = x;
  1147.                     break;
  1148.                 }
  1149.                 if (xyz_order != XYZ) {
  1150.                     x = this_iso->points[xdatum].x;
  1151.                     y = this_iso->points[xdatum].y;
  1152.                     z = this_iso->points[xdatum].z;
  1153.                 }
  1154.                 if (!parametric)
  1155.                     int_error("Must be in parametric mode.",
  1156.                           NO_CARET);
  1157.                    break;
  1158.                }
  1159.             case 1:         /* only one number on the line */
  1160.                if (!only_z)
  1161.                 int_error("3 columns expected, only 1 found", c_token);
  1162.                /* assign that number to z */
  1163.                this_iso->points[xdatum].z = x;
  1164.                z = x;
  1165.                this_iso->points[xdatum].x = xdatum;
  1166.                x = this_iso->points[xdatum].x;
  1167.                this_iso->points[xdatum].y = ydatum;
  1168.                y = this_iso->points[xdatum].y;
  1169.                if (parametric)
  1170.                 int_error("Must be in non parametric mode.",
  1171.                       NO_CARET);
  1172.                break;
  1173.             case 2:
  1174.                switch (xyz_order) {
  1175.                    case YX:
  1176.                    z = x;    /* Use z as temp */
  1177.                    x = y;
  1178.                    y = z;
  1179.                    break;
  1180.                    default:
  1181.                    break;
  1182.                }
  1183.                switch (mapping3d) {
  1184.                    case MAP3D_CARTESIAN:
  1185.                        int_error("2 columns found, 3 expected",
  1186.                          c_token);
  1187.                    break;
  1188.                    case MAP3D_SPHERICAL:
  1189.                    if (angles_format == ANGLES_DEGREES) {
  1190.                        x *= DEG2RAD; /* Convert to radians. */
  1191.                        y *= DEG2RAD;
  1192.                    }
  1193.                    this_iso->points[xdatum].x = cos(x) * cos(y);
  1194.                    this_iso->points[xdatum].y = sin(x) * cos(y);
  1195.                    this_iso->points[xdatum].z = sin(y);
  1196.                    break;
  1197.                    case MAP3D_CYLINDRICAL:
  1198.                    if (angles_format == ANGLES_DEGREES)
  1199.                        x *= DEG2RAD; /* Convert to radians. */
  1200.                    this_iso->points[xdatum].x = cos(x);
  1201.                    this_iso->points[xdatum].y = sin(x);
  1202.                    this_iso->points[xdatum].z = y;
  1203.                    break;
  1204.                }
  1205.                x = this_iso->points[xdatum].x;
  1206.                y = this_iso->points[xdatum].y;
  1207.                z = this_iso->points[xdatum].z;
  1208.                break;
  1209.             default:
  1210.                (void) sprintf(line, "bad data on line %d", l_num);
  1211.                int_error(line,c_token);
  1212.         }
  1213.  
  1214.         if (log_x) {
  1215.             if (x < 0.0)
  1216.             int_error("X value must be above 0 for log scale!",
  1217.                   NO_CARET);
  1218.             else
  1219.             this_iso->points[xdatum].x =
  1220.                 log10(this_iso->points[xdatum].x);
  1221.         }
  1222.         if (log_y) {
  1223.             if (y < 0.0)
  1224.             int_error("Y value must be above 0 for log scale!",
  1225.                   NO_CARET);
  1226.             else
  1227.             this_iso->points[xdatum].y =
  1228.                 log10(this_iso->points[xdatum].y);
  1229.         }
  1230.         if (log_z) {
  1231.             if (z < 0.0)
  1232.             int_error("Z value must be above 0 for log scale!",
  1233.                   NO_CARET);
  1234.             else
  1235.             this_iso->points[xdatum].z =
  1236.                 log10(this_iso->points[xdatum].z);
  1237.         }
  1238.  
  1239.         if (autoscale_lx) {
  1240.             if (x < xmin) xmin = x;
  1241.             if (x > xmax) xmax = x;
  1242.         }
  1243.         if (autoscale_ly) {
  1244.             if (y < ymin) ymin = y;
  1245.             if (y > ymax) ymax = y;
  1246.         }
  1247.         if (autoscale_lz) {
  1248.             if (z < zmin) zmin = z;
  1249.             if (z > zmax) zmax = z;
  1250.         }
  1251.  
  1252.         xdatum++;
  1253.     }
  1254.  
  1255.     if (xdatum > 0) {
  1256.         this_plot->num_iso_read++; /* Update last iso. */
  1257.         this_iso->p_count = xdatum;
  1258.  
  1259.         this_iso->next = this_plot->iso_crvs; 
  1260.         this_plot->iso_crvs = this_iso;
  1261.  
  1262.         if (xdatum != pt_in_iso_crv)
  1263.             this_plot->has_grid_topology = FALSE;
  1264.  
  1265.     }
  1266.     else {
  1267.         iso_free(this_iso);/* Free last allocation. */
  1268.     }
  1269.  
  1270. #ifdef unix
  1271.     if ( pipe_open ) {
  1272.         (void) pclose(fp);
  1273.         pipe_open = FALSE;
  1274.     } else
  1275. #endif
  1276.     (void) fclose(fp);
  1277.       if (this_plot->num_iso_read <= 1)
  1278.           this_plot->has_grid_topology = FALSE;
  1279.     if (this_plot->has_grid_topology) {
  1280.             struct iso_curve *new_icrvs = NULL;
  1281.         int num_new_iso = this_plot->iso_crvs->p_count,
  1282.             len_new_iso = this_plot->num_iso_read;
  1283.  
  1284.         /* Now we need to set the other direction (pseudo) isolines. */
  1285.             for (i = 0; i < num_new_iso; i++) {
  1286.             struct iso_curve *new_icrv = iso_alloc(len_new_iso);
  1287.  
  1288.             new_icrv->p_count = len_new_iso;
  1289.  
  1290.             for (j = 0, this_iso = this_plot->iso_crvs;
  1291.                  this_iso != NULL;
  1292.              j++, this_iso = this_iso->next) {
  1293.             new_icrv->points[j].x = this_iso->points[i].x;
  1294.                  new_icrv->points[j].y = this_iso->points[i].y;
  1295.                  new_icrv->points[j].z = this_iso->points[i].z;
  1296.             }
  1297.  
  1298.             new_icrv->next = new_icrvs;
  1299.             new_icrvs = new_icrv;
  1300.         }
  1301.  
  1302.         /* Append the new iso curves after the read ones. */
  1303.         for (this_iso = this_plot->iso_crvs;
  1304.              this_iso->next != NULL;
  1305.              this_iso = this_iso->next);
  1306.         this_iso->next = new_icrvs;
  1307.     }
  1308. }
  1309.  
  1310. /* print_points:
  1311.  * a debugging routine to print out the points of a curve,
  1312.  * and the curve structure. If curve<0, then we print the 
  1313.  * list of curves.
  1314.  */
  1315. static char *plot_type_names[4] = {
  1316.     "Function", "Data", "3D Function", "3d data"
  1317. };
  1318. static char *plot_style_names[6] = {
  1319.     "Lines", "Points", "Impulses", "LinesPoints", "Dots", "Errorbars"
  1320. };
  1321.  
  1322. print_points(curve)
  1323.     int curve;            /* which curve to print */
  1324. {
  1325.     register struct curve_points *this_plot;
  1326.     int i;
  1327.  
  1328.     if (curve < 0) {
  1329.        for (this_plot = first_plot, i=0; 
  1330.            this_plot != NULL; 
  1331.            i++, this_plot = this_plot->next_cp) {
  1332.           printf("Curve %d:\n", i);
  1333.           if ((int)this_plot->plot_type >= 0 && (int)(this_plot->plot_type) < 4)
  1334.             printf("Plot type %d: %s\n", (int)(this_plot->plot_type),
  1335.                  plot_type_names[(int)(this_plot->plot_type)]);
  1336.           else
  1337.             printf("Plot type %d: BAD\n", (int)(this_plot->plot_type));
  1338.           if ((int)this_plot->plot_style >= 0 && (int)(this_plot->plot_style) < 6)
  1339.             printf("Plot style %d: %s\n", (int)(this_plot->plot_style),
  1340.                  plot_style_names[(int)(this_plot->plot_style)]);
  1341.           else
  1342.             printf("Plot style %d: BAD\n", (int)(this_plot->plot_style));
  1343.           printf("Plot title: '%s'\n", this_plot->title);
  1344.           printf("Line type %d\n", this_plot->line_type);
  1345.           printf("Point type %d\n", this_plot->point_type);
  1346.           printf("max points %d\n", this_plot->p_max);
  1347.           printf("current points %d\n", this_plot->p_count);
  1348.           printf("\n");
  1349.        }
  1350.     } else {
  1351.        for (this_plot = first_plot, i = 0; 
  1352.            i < curve && this_plot != NULL; 
  1353.            i++, this_plot = this_plot->next_cp)
  1354.         ;
  1355.        if (this_plot == NULL)
  1356.         printf("Curve %d does not exist; list has %d curves\n", curve, i);
  1357.        else {
  1358.           printf ("Curve %d, %d points\n", curve, this_plot->p_count);
  1359.           for (i = 0; i < this_plot->p_count; i++) {
  1360.              printf("%c x=%g y=%g z=%g ylow=%g yhigh=%g\n", 
  1361.                    this_plot->points[i].type == INRANGE ? 'i'
  1362.                    : this_plot->points[i].type == OUTRANGE ? 'o'
  1363.                    : 'u',
  1364.                    this_plot->points[i].x,
  1365.                    this_plot->points[i].y,
  1366.                    this_plot->points[i].z,
  1367.                    this_plot->points[i].ylow,
  1368.                    this_plot->points[i].yhigh);
  1369.           }
  1370.           printf("\n");
  1371.        }
  1372.     }    
  1373. }
  1374.  
  1375. print_table()
  1376. {
  1377.     register struct curve_points *this_plot;
  1378.     int i, curve;
  1379.  
  1380.    for (this_plot = first_plot, curve = 0; this_plot != NULL;
  1381.        curve++, this_plot = this_plot->next_cp)
  1382.    {
  1383.       fprintf(outfile,"Curve %d, %d points\n", curve, this_plot->p_count);
  1384.       for (i = 0; i < this_plot->p_count; i++) {
  1385.          fprintf(outfile,"%c x=%g y=%g\n",
  1386.                this_plot->points[i].type == INRANGE ? 'i'
  1387.                : this_plot->points[i].type == OUTRANGE ? 'o'
  1388.                : 'u',
  1389.                this_plot->points[i].x,
  1390.                this_plot->points[i].y);
  1391.       }
  1392.       fprintf(outfile,"\n");
  1393.    }
  1394.    fflush(outfile);
  1395. }
  1396.  
  1397. print_3dtable()
  1398. {
  1399.     register struct surface_points *this_3dplot;
  1400.     int i, curve;
  1401.     struct gnuplot_contours *contours;      /* Not NULL If have contours. */
  1402.     struct iso_curve *isocrv;
  1403.  
  1404.     for (this_3dplot = first_3dplot, curve = 0; this_3dplot != NULL;
  1405.        curve++, this_3dplot = this_3dplot->next_sp)
  1406.     {
  1407.       isocrv = this_3dplot->iso_crvs;
  1408.       fprintf(outfile,"Curve %d, %d points\n", curve, isocrv->p_count);
  1409.       for (i = 0; i < isocrv->p_count; i++) {
  1410.          fprintf(outfile,"%c x=%g y=%g z=%g\n",
  1411.                isocrv->points[i].type == INRANGE ? 'i'
  1412.                : isocrv->points[i].type == OUTRANGE ? 'o'
  1413.                : 'u',
  1414.                isocrv->points[i].x,
  1415.                isocrv->points[i].y,
  1416.                isocrv->points[i].z);
  1417.       }
  1418.       fprintf(outfile,"\n");
  1419.    }
  1420.    fflush(outfile);
  1421. }
  1422.  
  1423. /* This parses the plot command after any range specifications. 
  1424.  * To support autoscaling on the x axis, we want any data files to 
  1425.  * define the x range, then to plot any functions using that range. 
  1426.  * We thus parse the input twice, once to pick up the data files, 
  1427.  * and again to pick up the functions. Definitions are processed 
  1428.  * twice, but that won't hurt.
  1429.  */
  1430. eval_plots()
  1431. {
  1432. register int i;
  1433. register struct curve_points *this_plot, **tp_ptr;
  1434. register int start_token, end_token;
  1435. register int begin_token;
  1436. double x_min, x_max, y_min, y_max;
  1437. register double x, xdiff, temp;
  1438. static struct value a;
  1439. BOOLEAN ltmp, some_data_files = FALSE;
  1440. int plot_num, line_num, point_num, xparam=0;
  1441. char *xtitle;
  1442. void parametric_fixup();
  1443.  
  1444.     if (autoscale_ly) {
  1445.         ymin = VERYLARGE;
  1446.         ymax = -VERYLARGE;
  1447.     } else if (log_y && (ymin <= 0.0 || ymax <= 0.0))
  1448.             int_error("y range must be above 0 for log scale!",
  1449.                 NO_CARET);
  1450.  
  1451.     tp_ptr = &(first_plot);
  1452.     plot_num = 0;
  1453.     line_num = 0;     /* default line type */
  1454.     point_num = 0;    /* default point type */
  1455.  
  1456.     xtitle = NULL;
  1457.  
  1458.     begin_token = c_token;
  1459.  
  1460. /*** First Pass: Read through data files ***/
  1461. /* This pass serves to set the xrange and to parse the command, as well 
  1462.  * as filling in every thing except the function data. That is done after
  1463.  * the xrange is defined.
  1464.  */
  1465.     while (TRUE) {
  1466.         if (END_OF_COMMAND)
  1467.             int_error("function to plot expected",c_token);
  1468.  
  1469.         start_token = c_token;
  1470.  
  1471.         if (is_definition(c_token)) {
  1472.             define();
  1473.         } else {
  1474.             plot_num++;
  1475.  
  1476.             if (isstring(c_token)) {            /* data file to plot */
  1477.                 if (parametric && xparam) 
  1478.                     int_error("previous parametric function not fully specified",
  1479.                                                                     c_token);
  1480.  
  1481.                 if (!some_data_files && autoscale_lx) {
  1482.                     xmin = VERYLARGE;
  1483.                     xmax = -VERYLARGE;
  1484.                 }
  1485.                 some_data_files = TRUE;
  1486.  
  1487.                 if (*tp_ptr)
  1488.                   this_plot = *tp_ptr;
  1489.                 else {        /* no memory malloc()'d there yet */
  1490.                     this_plot = cp_alloc(MIN_CRV_POINTS);
  1491.                     *tp_ptr = this_plot;
  1492.                 }
  1493.                 this_plot->plot_type = DATA;
  1494.                 this_plot->plot_style = data_style;
  1495.                 end_token = c_token;
  1496.                 get_data(this_plot); /* this also parses the using option */
  1497.             } 
  1498.             else {                            /* function to plot */
  1499.                 if (parametric)            /* working on x parametric function */
  1500.                     xparam = 1 - xparam;
  1501.                 if (*tp_ptr) {
  1502.                     this_plot = *tp_ptr;
  1503.                     cp_extend(this_plot, samples+1);
  1504.                 } else {        /* no memory malloc()'d there yet */
  1505.                     this_plot = cp_alloc(samples+1);
  1506.                     *tp_ptr = this_plot;
  1507.                 }
  1508.                 this_plot->plot_type = FUNC;
  1509.                 this_plot->plot_style = func_style;
  1510.                 dummy_func = &plot_func;
  1511.                 plot_func.at = temp_at();
  1512.                 /* ignore it for now */
  1513.                 end_token = c_token-1;
  1514.             }
  1515.  
  1516.             if (almost_equals(c_token,"t$itle")) {
  1517.                 if (parametric) {
  1518.                     if (xparam) 
  1519.                         int_error(
  1520.         "\"title\" allowed only after parametric function fully specified",
  1521.                                                                     c_token);
  1522.                     else if (xtitle != NULL)
  1523.                         xtitle[0] = '\0';  /* Remove default title .*/
  1524.                 }
  1525.                 c_token++;
  1526.                 if ( isstring( c_token ) ) {
  1527.                     m_quote_capture(&(this_plot->title),c_token,c_token);
  1528.                 }
  1529.                 else {
  1530.                     int_error("expecting \"title\" for plot",c_token);
  1531.                 }
  1532.                 c_token++;
  1533.             }
  1534.               else {
  1535.                   m_capture(&(this_plot->title),start_token,end_token);
  1536.                  if (xparam) xtitle = this_plot->title;
  1537.               }
  1538.   
  1539.               this_plot->line_type = line_num;
  1540.             this_plot->point_type = point_num;
  1541.  
  1542.             if (almost_equals(c_token,"w$ith")) {
  1543.                 if (parametric && xparam) 
  1544.                     int_error("\"with\" allowed only after parametric function fully specified",
  1545.                                     c_token);
  1546.                 this_plot->plot_style = get_style();
  1547.             }
  1548.  
  1549.             if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  1550.                 struct value t;
  1551.                 this_plot->line_type = (int)real(const_express(&t))-1;
  1552.             }
  1553.             if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  1554.                 struct value t;
  1555.                 this_plot->point_type = (int)real(const_express(&t))-1;
  1556.             }
  1557.             if ( (this_plot->plot_style == POINTS) ||
  1558.                  (this_plot->plot_style == LINESPOINTS) ||
  1559.                  (this_plot->plot_style == ERRORBARS) )
  1560.                     if (!xparam) point_num++;
  1561.             if (!xparam) line_num++;
  1562.  
  1563.             if (this_plot->plot_type == DATA) 
  1564.               /* now that we know the plot style, adjust the yrange */
  1565.               adjust_yrange(this_plot);
  1566.  
  1567.             tp_ptr = &(this_plot->next_cp);
  1568.         }
  1569.  
  1570.         if (equals(c_token,",")) 
  1571.             c_token++;
  1572.         else  
  1573.             break;
  1574.     }
  1575.  
  1576.     if (parametric && xparam) 
  1577.         int_error("parametric function not fully specified", NO_CARET);
  1578.  
  1579.     if (parametric) {
  1580.     /* Swap t and x ranges for duration of these eval_plot computations. */
  1581.         ltmp = autoscale_lx; autoscale_lx = autoscale_lt; autoscale_lt = ltmp;
  1582.         temp = xmin; xmin = tmin; tmin = temp;
  1583.         temp = xmax; xmax = tmax; tmax = temp;
  1584.     }
  1585.  
  1586. /*** Second Pass: Evaluate the functions ***/
  1587. /* Everything is defined now, except the function data. We expect
  1588.  * no syntax errors, etc, since the above parsed it all. This makes 
  1589.  * the code below simpler. If autoscale_ly, the yrange may still change.
  1590.  */
  1591.      if (fabs(xmax-xmin) < zero)
  1592.       if (autoscale_lx) {
  1593.          fprintf(stderr, "Warning: empty %c range [%g:%g], ", 
  1594.             parametric ? 't' : 'x', xmin,xmax);
  1595.          if (fabs(xmin) < zero) {
  1596.             /* completely arbitary */
  1597.             xmin = -1.;
  1598.             xmax = 1.;
  1599.          } else {
  1600.             /* expand range by 10% in either direction */
  1601.             xmin = xmin * 0.9;
  1602.             xmax = xmax * 1.1;
  1603.          }
  1604.          fprintf(stderr, "adjusting to [%g:%g]\n", xmin,xmax);
  1605.       } else {
  1606.          int_error("x range is less than `zero`", c_token);
  1607.       }
  1608.  
  1609.     /* give error if xrange badly set from missing datafile error */
  1610.     if (xmin == VERYLARGE || xmax == -VERYLARGE) {
  1611.         int_error("x range is invalid", c_token);
  1612.     }
  1613.  
  1614.     if (log_x) {
  1615.        if (xmin <= 0.0 || xmax <= 0.0)
  1616.         int_error("x range must be greater than 0 for log scale!",NO_CARET);
  1617.        x_min = log10(xmin);
  1618.        x_max = log10(xmax);
  1619.     } else {
  1620.        x_min = xmin;
  1621.        x_max = xmax;
  1622.     }
  1623.  
  1624.     xdiff = (x_max - x_min) / (samples - 1);
  1625.  
  1626.     tp_ptr = &(first_plot);
  1627.     plot_num = 0;
  1628.     this_plot = first_plot;
  1629.     c_token = begin_token;    /* start over */
  1630.  
  1631.     /* Read through functions */
  1632.     while (TRUE) {
  1633.         if (is_definition(c_token)) {
  1634.             define();
  1635.         } else {
  1636.             plot_num++;
  1637.             if (isstring(c_token)) {            /* data file to plot */
  1638.                 /* ignore this now */
  1639.                 c_token++;
  1640.                 if (almost_equals(c_token,"u$sing")) {
  1641.                     c_token++;      /* skip "using" */
  1642.                         if (!isstring(c_token)) {
  1643.                         struct value a;
  1644.                         (void)magnitude(const_express(&a)); /* skip xcol */
  1645.                         if (equals(c_token,":")) {
  1646.                             c_token++;      /* skip ":" */
  1647.                             (void)magnitude(const_express(&a)); /* skip ycol */
  1648.                         }
  1649.                         if (equals(c_token,":")) {
  1650.                             c_token++;      /* skip ":" */
  1651.                             (void)magnitude(const_express(&a)); /* skip yemin */
  1652.                         }
  1653.                         if (equals(c_token,":")) {
  1654.                             c_token++;      /* skip ":" */
  1655.                             (void)magnitude(const_express(&a)); /* skip yemax */
  1656.                         }
  1657.                     }
  1658.                     if (isstring(c_token))
  1659.                         c_token++;      /* skip format string */
  1660.                 }
  1661.             }
  1662.             else {                    /* function to plot */
  1663.                 if (parametric)            /* working on x parametric function */
  1664.                     xparam = 1 - xparam;
  1665.                 dummy_func = &plot_func;
  1666.                 plot_func.at = temp_at(); /* reparse function */
  1667.  
  1668.                 for (i = 0; i < samples; i++) {
  1669.                     x = x_min + i*xdiff;
  1670.                     /* if (log_x) PEM fix logscale x axis */
  1671.                     /* x = pow(10.0,x); 26-Sep-89 */
  1672.                     (void) complex(&plot_func.dummy_values[0],
  1673.                                 log_x ? pow(10.0,x) : x,
  1674.                                 0.0);
  1675.  
  1676.                     evaluate_at(plot_func.at,&a);
  1677.  
  1678.                     if (undefined || (fabs(imag(&a)) > zero)) {
  1679.                        this_plot->points[i].type = UNDEFINED;
  1680.                        continue;
  1681.                     }
  1682.  
  1683.                     temp = real(&a);
  1684.  
  1685.                     if (log_y && temp < 0.0) {
  1686.                        this_plot->points[i].type = UNDEFINED;
  1687.                        continue;
  1688.                     }
  1689.  
  1690.                     this_plot->points[i].x = x;
  1691.                     if (log_y) {
  1692.                        if (temp == 0.0) {
  1693.                           this_plot->points[i].type = OUTRANGE;
  1694.                           this_plot->points[i].y = -VERYLARGE;
  1695.                           continue;
  1696.                        } else {
  1697.                           this_plot->points[i].y = log10(temp);
  1698.                        }
  1699.                     } else
  1700.                      this_plot->points[i].y = temp;
  1701.  
  1702.                     if (autoscale_ly || polar
  1703.                        || inrange(temp, ymin, ymax)) {
  1704.                        this_plot->points[i].type = INRANGE;
  1705.                     /* When xparam is 1 we are not really computing y's! */
  1706.                         if (!xparam && autoscale_ly) {
  1707.                            if (temp < ymin) ymin = temp;
  1708.                            if (temp > ymax) ymax = temp;
  1709.                         }
  1710.                     } else
  1711.                      this_plot->points[i].type = OUTRANGE;
  1712.                 }
  1713.                 this_plot->p_count = i; /* samples */
  1714.              }
  1715.  
  1716.             /* title was handled above */
  1717.             if (almost_equals(c_token,"t$itle")) {
  1718.                 c_token++;
  1719.                 c_token++;
  1720.             }
  1721.  
  1722.             /* style was handled above */
  1723.             if (almost_equals(c_token,"w$ith")) {
  1724.                 c_token++;
  1725.                 c_token++;
  1726.             }
  1727.  
  1728.             /* line and point types were handled above */
  1729.             if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  1730.                 struct value t;
  1731.                 (void)real(const_express(&t));
  1732.             }
  1733.             if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  1734.                 struct value t;
  1735.                 (void)real(const_express(&t));
  1736.             }
  1737.  
  1738.              tp_ptr = &(this_plot->next_cp); /* used below */
  1739.             this_plot = this_plot->next_cp;
  1740.          }
  1741.         
  1742.         if (equals(c_token,",")) 
  1743.           c_token++;
  1744.         else  
  1745.           break;
  1746.      }
  1747.  
  1748.     /* throw out all curve_points at end of list, that we don't need  */
  1749.     cp_free(*tp_ptr);
  1750.     *tp_ptr = NULL;
  1751.  
  1752.     if (fabs(ymax - ymin) < zero)
  1753.      /* if autoscale, widen range */
  1754.      if (autoscale_ly) {
  1755.         fprintf(stderr, "Warning: empty y range [%g:%g], ", ymin, ymax);
  1756.         if (fabs(ymin) < zero) {
  1757.             ymin = -1.;
  1758.             ymax = 1.;
  1759.         } else {
  1760.             /* expand range by 10% in either direction */
  1761.             ymin = ymin * 0.9;
  1762.             ymax = ymax * 1.1;
  1763.         }
  1764.         fprintf(stderr, "adjusting to [%g:%g]\n", ymin, ymax);
  1765.      } else {
  1766.         int_error("y range is less than `zero`", c_token);
  1767.      }
  1768.  
  1769. /* Now we finally know the real ymin and ymax */
  1770.     if (log_y) {
  1771.         y_min = log10(ymin);
  1772.         y_max = log10(ymax);
  1773.     } else {
  1774.         y_min = ymin;
  1775.         y_max = ymax;
  1776.     }
  1777.     capture(replot_line,plot_token,c_token);
  1778.  
  1779.     if (parametric) {
  1780.     /* Now put t and x ranges back before we actually plot anything. */
  1781.         ltmp = autoscale_lx; autoscale_lx = autoscale_lt; autoscale_lt = ltmp;
  1782.         temp = xmin; xmin = tmin; tmin = temp;
  1783.         temp = xmax; xmax = tmax; tmax = temp;
  1784.         if (some_data_files && autoscale_lx) {
  1785.         /* 
  1786.             Stop any further autoscaling in this case (may be a mistake, have
  1787.               to consider what is really wanted some day in the future--jdc). 
  1788.         */
  1789.             autoscale_lx = 0;
  1790.         }
  1791.     /* Now actually fix the plot pairs to be single plots. */
  1792.         parametric_fixup (first_plot, &plot_num, &x_min, &x_max);
  1793.     }
  1794.  
  1795.     if (strcmp(term_tbl[term].name,"table") == 0)
  1796.         print_table();
  1797.     else
  1798.         do_plot(first_plot,plot_num,x_min,x_max,y_min,y_max);
  1799.     cp_free(first_plot);
  1800.     first_plot = NULL;
  1801. }
  1802.  
  1803. /* This parses the splot command after any range specifications. 
  1804.  * To support autoscaling on the x/z axis, we want any data files to 
  1805.  * define the x/y range, then to plot any functions using that range. 
  1806.  * We thus parse the input twice, once to pick up the data files, 
  1807.  * and again to pick up the functions. Definitions are processed 
  1808.  * twice, but that won't hurt.
  1809.  */
  1810. eval_3dplots()
  1811. {
  1812. register int i,j,k;
  1813. register struct surface_points *this_plot, **tp_3d_ptr;
  1814. register int start_token, end_token;
  1815. register int begin_token;
  1816. double x_min, x_max, y_min, y_max, z_min, z_max;
  1817. register double x, xdiff, xisodiff, y, ydiff, yisodiff, temp;
  1818. static struct value a;
  1819. BOOLEAN ltmp, some_data_files = FALSE;
  1820. int plot_num, line_num, point_num,
  1821.     crnt_param = 0; /* 0=x, 1=y, 2=z */
  1822. char *xtitle;
  1823. char *ytitle;
  1824. void parametric_3dfixup();
  1825.  
  1826.     if (autoscale_lz) {
  1827.         zmin = VERYLARGE;
  1828.         zmax = -VERYLARGE;
  1829.     } else if (log_z && (zmin <= 0.0 || zmax <= 0.0))
  1830.             int_error("z range must be above 0 for log scale!",
  1831.                 NO_CARET);
  1832.  
  1833.     tp_3d_ptr = &(first_3dplot);
  1834.     plot_num = 0;
  1835.     line_num = 0;     /* default line type */
  1836.     point_num = 0;    /* default point type */
  1837.  
  1838.     xtitle = NULL;
  1839.     ytitle = NULL;
  1840.  
  1841.     begin_token = c_token;
  1842.  
  1843. /*** First Pass: Read through data files ***/
  1844. /* This pass serves to set the x/yranges and to parse the command, as well 
  1845.  * as filling in every thing except the function data. That is done after
  1846.  * the x/yrange is defined.
  1847.  */
  1848.     while (TRUE) {
  1849.         if (END_OF_COMMAND)
  1850.             int_error("function to plt3d expected",c_token);
  1851.  
  1852.         start_token = c_token;
  1853.  
  1854.         if (is_definition(c_token)) {
  1855.             define();
  1856.         } else {
  1857.             plot_num++;
  1858.  
  1859.             if (isstring(c_token)) {            /* data file to plot */
  1860.                 if (parametric && crnt_param != 0)
  1861.                     int_error("previous parametric function not fully specified",
  1862.                                                                     c_token);
  1863.  
  1864.                 if (!some_data_files) {
  1865.                     if (autoscale_lx) {
  1866.                         xmin = VERYLARGE;
  1867.                         xmax = -VERYLARGE;
  1868.                     }
  1869.                     if (autoscale_ly) {
  1870.                         ymin = VERYLARGE;
  1871.                         ymax = -VERYLARGE;
  1872.                     }
  1873.                 }
  1874.  
  1875.                 some_data_files = TRUE;
  1876.  
  1877.                 if (*tp_3d_ptr)
  1878.                     this_plot = *tp_3d_ptr;
  1879.                 else {    /* no memory malloc()'d there yet */
  1880.                     /* Allocate samples * iso_samples twice for */
  1881.                     /* Each of the isoparametric direction. */
  1882.                     this_plot = sp_alloc(0,0);
  1883.                     *tp_3d_ptr = this_plot;
  1884.                 }
  1885.  
  1886.                 this_plot->plot_type = DATA3D;
  1887.                 this_plot->plot_style = data_style;
  1888.                 end_token = c_token;
  1889.                 get_3ddata(this_plot); /* this also parses the using option */
  1890.             } 
  1891.             else {                        /* function to plot */
  1892.                 if (parametric) /* Rotate between x/y/z axes */
  1893.                     crnt_param = (crnt_param+1) % 3;
  1894.                 if (*tp_3d_ptr) {
  1895.                     this_plot = *tp_3d_ptr;
  1896.                     sp_replace(this_plot,samples,2*iso_samples);
  1897.                 }
  1898.                 else {    /* no memory malloc()'d there yet */
  1899.                     /* Allocate samples * iso_samples twice for */
  1900.                     /* Each of the isoparametric direction. */
  1901.                     this_plot = sp_alloc(samples,2*iso_samples);
  1902.                     *tp_3d_ptr = this_plot;
  1903.                 }
  1904.  
  1905.                 this_plot->plot_type = FUNC3D;
  1906.                 this_plot->has_grid_topology = TRUE;
  1907.                 this_plot->plot_style = func_style;
  1908.                 dummy_func = &plot_func;
  1909.                 plot_func.at = temp_at();
  1910.                 /* ignore it for now */
  1911.                 end_token = c_token-1;
  1912.             }
  1913.  
  1914.             if (almost_equals(c_token,"t$itle")) {
  1915.                 if (parametric) {
  1916.                         if (crnt_param)
  1917.                         int_error(
  1918.         "\"title\" allowed only after parametric function fully specified",
  1919.                                                                     c_token);
  1920.                     else {
  1921.                         /* Remove default title */
  1922.                         if (xtitle != NULL)
  1923.                             xtitle[0] = '\0';
  1924.                         if (ytitle != NULL)
  1925.                             ytitle[0] = '\0';
  1926.                     }
  1927.                     }
  1928.                 c_token++;
  1929.                 if ( isstring( c_token ) ) {
  1930.                     m_quote_capture(&(this_plot->title),c_token,c_token);
  1931.                 }
  1932.                 else {
  1933.                     int_error("expecting \"title\" for plot",c_token);
  1934.                 }
  1935.                 c_token++;
  1936.             }
  1937.               else {
  1938.                   m_capture(&(this_plot->title),start_token,end_token);
  1939.                 if (crnt_param == 1) xtitle = this_plot->title;
  1940.                 if (crnt_param == 2) ytitle = this_plot->title;
  1941.               }
  1942.   
  1943.               this_plot->line_type = line_num;
  1944.             this_plot->point_type = point_num;
  1945.  
  1946.             if (almost_equals(c_token,"w$ith")) {
  1947.                 this_plot->plot_style = get_style();
  1948.             }
  1949.  
  1950.             if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  1951.                 struct value t;
  1952.                 this_plot->line_type = (int)real(const_express(&t))-1;
  1953.             }
  1954.             if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  1955.                 struct value t;
  1956.                 this_plot->point_type = (int)real(const_express(&t))-1;
  1957.             }
  1958.             if ( (this_plot->plot_style == POINTS) ||
  1959.                  (this_plot->plot_style == LINESPOINTS) ||
  1960.                  (this_plot->plot_style == ERRORBARS) )
  1961.                     if (crnt_param == 0)
  1962.                         point_num +=
  1963.                             1 + (draw_contour != 0)
  1964.                               + (hidden3d != 0);
  1965.             if (crnt_param == 0)
  1966.                 line_num += 1 + (draw_contour != 0)
  1967.                               + (hidden3d != 0);
  1968.  
  1969.             tp_3d_ptr = &(this_plot->next_sp);
  1970.         }
  1971.  
  1972.         if (equals(c_token,",")) 
  1973.             c_token++;
  1974.         else  
  1975.             break;
  1976.     }
  1977.  
  1978.     if (parametric && crnt_param != 0)
  1979.         int_error("parametric function not fully specified", NO_CARET);
  1980.  
  1981.     if (parametric) {
  1982.     /* Swap u/v and x/y ranges for duration of these eval_plot computations. */
  1983.         ltmp = autoscale_lx; autoscale_lx = autoscale_lu; autoscale_lu = ltmp;
  1984.         ltmp = autoscale_ly; autoscale_ly = autoscale_lv; autoscale_lv = ltmp;
  1985.         temp = xmin; xmin = umin; umin = temp;
  1986.         temp = xmax; xmax = umax; umax = temp;
  1987.         temp = ymin; ymin = vmin; vmin = temp;
  1988.         temp = ymax; ymax = vmax; vmax = temp;
  1989.     }
  1990. /*** Second Pass: Evaluate the functions ***/
  1991. /* Everything is defined now, except the function data. We expect
  1992.  * no syntax errors, etc, since the above parsed it all. This makes 
  1993.  * the code below simpler. If autoscale_ly, the yrange may still change.
  1994.  */
  1995.      if (xmin == xmax)
  1996.       if (autoscale_lx) {
  1997.          fprintf(stderr, "Warning: empty x range [%g:%g], ", 
  1998.              xmin,xmax);
  1999.          if (xmin == 0.0) {
  2000.             /* completely arbitary */
  2001.             xmin = -1.;
  2002.             xmax = 1.;
  2003.          } else {
  2004.             /* expand range by 10% in either direction */
  2005.             xmin = xmin * 0.9;
  2006.             xmax = xmax * 1.1;
  2007.          }
  2008.          fprintf(stderr, "adjusting to [%g:%g]\n", xmin,xmax);
  2009.       } else {
  2010.          int_error("x range is empty", c_token);
  2011.       }
  2012.  
  2013.      if (ymin == ymax)
  2014.       if (autoscale_ly) {
  2015.          fprintf(stderr, "Warning: empty y range [%g:%g], ", 
  2016.             ymin,ymax);
  2017.          if (ymin == 0.0) {
  2018.             /* completely arbitary */
  2019.             ymin = -1.;
  2020.             ymax = 1.;
  2021.          } else {
  2022.             /* expand range by 10% in either direction */
  2023.             ymin = ymin * 0.9;
  2024.             ymax = ymax * 1.1;
  2025.          }
  2026.          fprintf(stderr, "adjusting to [%g:%g]\n", ymin,ymax);
  2027.       } else {
  2028.          int_error("y range is empty", c_token);
  2029.       }
  2030.  
  2031.     /* give error if xrange badly set from missing datafile error */
  2032.     if (xmin == VERYLARGE || xmax == -VERYLARGE) {
  2033.     int_error("x range is invalid", c_token);
  2034.     }
  2035.  
  2036.     if (log_x) {
  2037.        if (xmin <= 0.0 || xmax <= 0.0)
  2038.         int_error("x range must be greater than 0 for log scale!",NO_CARET);
  2039.        x_min = log10(xmin);
  2040.        x_max = log10(xmax);
  2041.     } else {
  2042.        x_min = xmin;
  2043.        x_max = xmax;
  2044.     }
  2045.  
  2046.     if (log_y) {
  2047.        if (ymin <= 0.0 || ymax <= 0.0)
  2048.         int_error("y range must be greater than 0 for log scale!",NO_CARET);
  2049.        y_min = log10(ymin);
  2050.        y_max = log10(ymax);
  2051.     } else {
  2052.        y_min = ymin;
  2053.        y_max = ymax;
  2054.     }
  2055.  
  2056.     if (samples < 2 || iso_samples < 2)
  2057.     int_error("samples or iso_samples < 2. Must be at least 2.\n");
  2058.  
  2059.     xdiff = (x_max - x_min) / (samples - 1);
  2060.     ydiff = (y_max - y_min) / (samples - 1);
  2061.     xisodiff = (x_max - x_min) / (iso_samples - 1);
  2062.     yisodiff = (y_max - y_min) / (iso_samples - 1);
  2063.  
  2064.     plot_num = 0;
  2065.     this_plot = first_3dplot;
  2066.     c_token = begin_token;    /* start over */
  2067.  
  2068.     /* Read through functions */
  2069.     while (TRUE) {
  2070.         if (is_definition(c_token)) {
  2071.             define();
  2072.         } else {
  2073.             plot_num++;
  2074.             if (isstring(c_token)) {            /* data file to plot */
  2075.                 /* ignore this now */
  2076.                 c_token++;
  2077.                 if (almost_equals(c_token,"u$sing")) {
  2078.                     c_token++;      /* skip "using" */
  2079.                                 if (!isstring(c_token)) {
  2080.                         struct value a;
  2081.                         (void)magnitude(const_express(&a));    /* skip xcol */
  2082.                         if (equals(c_token,":")) {
  2083.                             c_token++;    /* skip ":" */
  2084.                             (void)magnitude(const_express(&a));    /* skip ycol */
  2085.                             if (equals(c_token,":")) {
  2086.                                 c_token++;    /* skip ":" */
  2087.                                 (void)magnitude(const_express(&a));    /* skip zcol */
  2088.                             }
  2089.                         }
  2090.                     }
  2091.                                 if (isstring(c_token))
  2092.                         c_token++;    /* skip format string */
  2093.                 }
  2094.             }
  2095.             else {                    /* function to plot */
  2096.                 struct iso_curve *this_iso = this_plot->iso_crvs;
  2097.                 struct coordinate *points = this_iso->points;
  2098.                 
  2099.                 if (parametric)
  2100.                     crnt_param = (crnt_param+1) % 3;
  2101.                 dummy_func = &plot_func;
  2102.                 plot_func.at = temp_at(); /* reparse function */
  2103.  
  2104.                 for (j = 0; j < iso_samples; j++) {
  2105.                     y = y_min + j*yisodiff;
  2106.                     /* if (log_y) PEM fix logscale y axis */
  2107.                     /* y = pow(10.0,y); 26-Sep-89 */
  2108.                     (void) complex(&plot_func.dummy_values[1],
  2109.                                 log_y ? pow(10.0,y) : y,
  2110.                                 0.0);
  2111.  
  2112.                     for (i = 0; i < samples; i++) {
  2113.                         x = x_min + i*xdiff;
  2114.                         /* if (log_x) PEM fix logscale x axis */
  2115.                         /* x = pow(10.0,x); 26-Sep-89 */
  2116.                         (void) complex(&plot_func.dummy_values[0],
  2117.                                 log_x ? pow(10.0,x) : x,
  2118.                                 0.0);
  2119.  
  2120.                         points[i].x = x;
  2121.                         points[i].y = y;
  2122.  
  2123.                         evaluate_at(plot_func.at,&a);
  2124.  
  2125.                         if (undefined || (fabs(imag(&a)) > zero)) {
  2126.                        points[i].type = UNDEFINED;
  2127.                        continue;
  2128.                         }
  2129.  
  2130.                         temp = real(&a);
  2131.  
  2132.                         if (log_z && temp < 0.0) {
  2133.                        points[i].type = UNDEFINED;
  2134.                        continue;
  2135.                         }
  2136.  
  2137.                         if (log_z) {
  2138.                        if (temp == 0.0) {
  2139.                           points[i].type = OUTRANGE;
  2140.                           points[i].z = -VERYLARGE;
  2141.                           continue;
  2142.                        } else {
  2143.                           points[i].z = log10(temp);
  2144.                        }
  2145.                         } else
  2146.                        points[i].z = temp;
  2147.  
  2148.                         if (autoscale_lz
  2149.                        || inrange(temp, zmin, zmax)) {
  2150.                        points[i].type = INRANGE;
  2151.                        if (autoscale_lz) {
  2152.                           if (temp < zmin) zmin = temp;
  2153.                           if (temp > zmax) zmax = temp;
  2154.                        }
  2155.                         } else
  2156.                        points[i].type = OUTRANGE;
  2157.                     }
  2158.                     this_iso->p_count = samples;
  2159.                     this_iso = this_iso->next;
  2160.                     points = this_iso->points;
  2161.                 }
  2162.  
  2163.                 for (i = 0; i < iso_samples; i++) {
  2164.                     x = x_min + i*xisodiff;
  2165.                     /* if (log_x) PEM fix logscale x axis */
  2166.                     /* x = pow(10.0,x); 26-Sep-89 */
  2167.                     (void) complex(&plot_func.dummy_values[0],
  2168.                                 log_x ? pow(10.0,x) : x,
  2169.                                 0.0);
  2170.  
  2171.                     for (j = 0; j < samples; j++) {
  2172.                         y = y_min + j*ydiff;
  2173.                         /* if (log_y) PEM fix logscale y axis */
  2174.                         /* y = pow(10.0,y); 26-Sep-89 */
  2175.                         (void) complex(&plot_func.dummy_values[1],
  2176.                                 log_y ? pow(10.0,y) : y,
  2177.                                 0.0);
  2178.  
  2179.                         points[j].x = x;
  2180.                         points[j].y = y;
  2181.  
  2182.                         evaluate_at(plot_func.at,&a);
  2183.  
  2184.                         if (undefined || (fabs(imag(&a)) > zero)) {
  2185.                        points[j].type = UNDEFINED;
  2186.                        continue;
  2187.                         }
  2188.  
  2189.                         temp = real(&a);
  2190.  
  2191.                         if (log_z && temp < 0.0) {
  2192.                        points[j].type = UNDEFINED;
  2193.                        continue;
  2194.                         }
  2195.  
  2196.                         if (log_z) {
  2197.                        if (temp == 0.0) {
  2198.                           points[j].type = OUTRANGE;
  2199.                           points[j].z = -VERYLARGE;
  2200.                           continue;
  2201.                        } else {
  2202.                           points[j].z = log10(temp);
  2203.                        }
  2204.                         } else
  2205.                        points[j].z = temp;
  2206.  
  2207.                         if (autoscale_lz
  2208.                        || inrange(temp, zmin, zmax)) {
  2209.                        points[j].type = INRANGE;
  2210.                        if (autoscale_lz) {
  2211.                           if (temp < zmin) zmin = temp;
  2212.                           if (temp > zmax) zmax = temp;
  2213.                        }
  2214.                         } else
  2215.                        points[j].type = OUTRANGE;
  2216.                     }
  2217.                         this_iso->p_count = samples;
  2218.                     this_iso = this_iso->next;
  2219.                     points = this_iso ? this_iso->points : NULL;
  2220.                 }
  2221.              }
  2222.  
  2223.             /* title was handled above */
  2224.             if (almost_equals(c_token,"t$itle")) {
  2225.                 c_token++;
  2226.                 c_token++;
  2227.             }
  2228.  
  2229.             /* style was handled above */
  2230.             if (almost_equals(c_token,"w$ith")) {
  2231.                 c_token++;
  2232.                 c_token++;
  2233.             }
  2234.  
  2235.             /* line and point types were handled above */
  2236.             if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  2237.                 struct value t;
  2238.                 (void)real(const_express(&t));
  2239.             }
  2240.             if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  2241.                 struct value t;
  2242.                 (void)real(const_express(&t));
  2243.             }
  2244.  
  2245.             this_plot = this_plot->next_sp;
  2246.          }
  2247.  
  2248.         if (equals(c_token,","))
  2249.           c_token++;
  2250.         else
  2251.           break;
  2252.      }
  2253.  
  2254.     if (fabs(zmax - zmin) < zero)
  2255.      /* if autoscale, widen range */
  2256.      if (autoscale_lz) {
  2257.         fprintf(stderr, "Warning: empty z range [%g:%g], ", zmin, zmax);
  2258.         if (fabs(zmin) < zero ) {
  2259.             zmin = -1.;
  2260.             zmax = 1.;
  2261.         } else {
  2262.             /* expand range by 10% in either direction */
  2263.             zmin = zmin * 0.9;
  2264.             zmax = zmax * 1.1;
  2265.         }
  2266.         fprintf(stderr, "adjusting to [%g:%g]\n", zmin, zmax);
  2267.      } else {
  2268.         int_error("z range is less than `zero`", c_token);
  2269.      }
  2270.  
  2271. /* Now we finally know the real zmin and zmax */
  2272.     if (log_z) {
  2273.         if (zmin <= 0.0 || zmax <= 0.0)
  2274.             int_error("z range must be greater than 0 for log scale!",NO_CARET);
  2275.         z_min = log10(zmin);
  2276.         z_max = log10(zmax);
  2277.     } else {
  2278.         z_min = zmin;
  2279.         z_max = zmax;
  2280.     }
  2281.     capture(replot_line,plot_token,c_token);
  2282.  
  2283.     if (parametric) {
  2284.     /* Now put u/v and x/y ranges back before we actually plot anything. */
  2285.         ltmp = autoscale_lx; autoscale_lx = autoscale_lu; autoscale_lu = ltmp;
  2286.         ltmp = autoscale_ly; autoscale_ly = autoscale_lv; autoscale_lv = ltmp;
  2287.         temp = xmin; xmin = umin; umin = temp;
  2288.         temp = xmax; xmax = umax; umax = temp;
  2289.         temp = ymin; ymin = vmin; vmin = temp;
  2290.         temp = ymax; ymax = vmax; vmax = temp;
  2291.  
  2292.     /* Now actually fix the plot triplets to be single plots. */
  2293.         parametric_3dfixup(first_3dplot, &plot_num,
  2294.                    &x_min, &x_max, &y_min, &y_max,
  2295.                    &z_min, &z_max);
  2296.         if (log_x) {
  2297.             if (x_min <= 0.0 || x_max <= 0.0)
  2298.                 int_error("x range must be greater than 0 for log scale!",NO_CARET);
  2299.             x_min = log10(x_min);
  2300.             x_max = log10(x_max);
  2301.         }
  2302.  
  2303.         if (log_y) {
  2304.             if (y_min <= 0.0 || y_max <= 0.0)
  2305.                 int_error("y range must be greater than 0 for log scale!",NO_CARET);
  2306.             y_min = log10(y_min);
  2307.             y_max = log10(y_max);
  2308.         }
  2309.  
  2310.         if (log_z) {
  2311.             if (z_min <= 0.0 || z_max <= 0.0)
  2312.                 int_error("z range must be greater than 0 for log scale!",NO_CARET);
  2313.             z_min = log10(z_min);
  2314.             z_max = log10(z_max);
  2315.         }
  2316.     }
  2317.  
  2318.  
  2319.     /* Creates contours if contours are to be plotted as well. */
  2320.     if (draw_contour) {
  2321.         for (this_plot=first_3dplot, i=0;
  2322.              i < plot_num;
  2323.              this_plot=this_plot->next_sp, i++) {
  2324.             if (this_plot->contours) {
  2325.                 struct gnuplot_contours *cntr, *cntrs = this_plot->contours;
  2326.  
  2327.                 while (cntrs) {
  2328.                     cntr = cntrs;
  2329.                     cntrs = cntrs->next;
  2330.                     free(cntr->coords);
  2331.                     free(cntr);
  2332.                 }
  2333.             }
  2334.             /* Make sure this one can be contoured. */
  2335.             if (!this_plot->has_grid_topology) {
  2336.                 this_plot->contours = NULL;
  2337.                 int_error("Can not contour non grid data!",NO_CARET);
  2338.             }
  2339.             if (this_plot->plot_type == DATA3D)
  2340.                 this_plot->contours = contour(
  2341.                            this_plot->num_iso_read,
  2342.                            this_plot->iso_crvs,
  2343.                            contour_levels, contour_pts,
  2344.                            contour_kind, contour_order);
  2345.             else
  2346.                 this_plot->contours = contour(iso_samples,
  2347.                            this_plot->iso_crvs,
  2348.                            contour_levels, contour_pts,
  2349.                            contour_kind, contour_order);
  2350.         }
  2351.     }
  2352.  
  2353.     if (strcmp(term_tbl[term].name,"table") == 0)
  2354.        print_3dtable();
  2355.     else
  2356.        do_3dplot(first_3dplot,plot_num,x_min,x_max,y_min,y_max,z_min,z_max);
  2357.     sp_free(first_3dplot);
  2358.     first_3dplot = NULL;
  2359. }
  2360.  
  2361. done(status)
  2362. int status;
  2363. {
  2364.     if (term && term_init)
  2365.         (*term_tbl[term].reset)();
  2366. #ifdef vms
  2367.     vms_reset();
  2368. #endif
  2369.     exit(status);
  2370. }
  2371.  
  2372. void parametric_fixup (start_plot, plot_num, x_min, x_max)
  2373. struct curve_points *start_plot;
  2374. int *plot_num;
  2375. double *x_min, *x_max;
  2376. /*
  2377.     The hardest part of this routine is collapsing the FUNC plot types
  2378.    in the list (which are gauranteed to occur in (x,y) pairs while 
  2379.     preserving the non-FUNC type plots intact.  This means we have to
  2380.     work our way through various lists.  Examples (hand checked):
  2381.         start_plot:F1->F2->NULL ==> F2->NULL
  2382.         start_plot:F1->F2->F3->F4->F5->F6->NULL ==> F2->F4->F6->NULL
  2383.         start_plot:F1->F2->D1->D2->F3->F4->D3->NULL ==> F2->D1->D2->F4->D3->NULL
  2384.     
  2385.     Of course, the more interesting work is to move the y values of
  2386.     the x function to become the x values of the y function (checking
  2387.     the mins and maxs as we go along).
  2388. */
  2389. {
  2390.     struct curve_points *xp, *new_list, *yp = start_plot, *tmp, 
  2391.             *free_list, *free_head=NULL;
  2392.     int i, tlen, curve; 
  2393.     char *new_title;
  2394.     double lxmin, lxmax, temp;
  2395.  
  2396.     if (autoscale_lx) {
  2397.         lxmin = VERYLARGE;
  2398.         lxmax = -VERYLARGE;
  2399.     } else {
  2400.         lxmin = xmin;
  2401.         lxmax = xmax;
  2402.     }
  2403.  
  2404. /* 
  2405.     Ok, go through all the plots and move FUNC types together.  Note: this
  2406.     originally was written to look for a NULL next pointer, but gnuplot 
  2407.     wants to be sticky in grabbing memory and the right number of items
  2408.     in the plot list is controlled by the plot_num variable.
  2409.  
  2410.     Since gnuplot wants to do this sticky business, a free_list of 
  2411.     curve_points is kept and then tagged onto the end of the plot list as
  2412.     this seems more in the spirit of the original memory behavior than
  2413.     simply freeing the memory.  I'm personally not convinced this sort
  2414.     of concern is worth it since the time spent computing points seems
  2415.     to dominate any garbage collecting that might be saved here...
  2416. */
  2417.     new_list = xp = start_plot; 
  2418.     yp = xp->next_cp;
  2419.    curve = 0;
  2420.     for (; curve < *plot_num; xp = xp->next_cp,yp = yp->next_cp,curve++) {
  2421.         if (xp->plot_type != FUNC) {
  2422.             continue;
  2423.         }
  2424.     /* Here's a FUNC parametric function defined as two parts. */
  2425.         --(*plot_num);
  2426.     /* 
  2427.         Go through all the points assigning the y's from xp to be the
  2428.         x's for yp.  Check max's and min's as you go.
  2429.     */
  2430.         for (i = 0; i < yp->p_count; ++i) {
  2431.         /* 
  2432.             Throw away excess xp points, mark excess yp points as OUTRANGE.
  2433.         */
  2434.             if (i > xp->p_count) {
  2435.                 yp->points[i].type = OUTRANGE;
  2436.                 continue;
  2437.             }
  2438.         /* 
  2439.             Just as we had to do when we computed y values--now check that
  2440.             x's (computed parametrically) are in the permitted ranges as well.
  2441.         */
  2442.             temp = xp->points[i].y;   /* New x value for yp function. */
  2443.             yp->points[i].x = temp;
  2444.         /* Handle undefined values differently from normal ranges. */
  2445.             if (xp->points[i].type == UNDEFINED)
  2446.                 yp->points[i].type = xp->points[i].type;  
  2447.             if (autoscale_lx || polar
  2448.                        || inrange(temp, lxmin, lxmax)) {
  2449.                if (autoscale_lx && temp < lxmin) lxmin = temp;
  2450.                 if (autoscale_lx && temp > lxmax) lxmax = temp;
  2451.             } else
  2452.             yp->points[i].type = OUTRANGE;  /* Due to x value. */
  2453.         }
  2454.    /* Ok, fix up the title to include both the xp and yp plots. */
  2455.         if (xp->title && xp->title[0] != '\0') {
  2456.             tlen = strlen (yp->title) + strlen (xp->title) + 3;
  2457.           new_title = alloc ((unsigned int) tlen, "string");
  2458.             strcpy (new_title, xp->title);  
  2459.             strcat (new_title, ", ");       /* + 2 */
  2460.             strcat (new_title, yp->title);  /* + 1 = + 3 */
  2461.             free (yp->title);
  2462.             yp->title = new_title;
  2463.         }
  2464.     /* Eliminate the first curve (xparam) and just use the second. */
  2465.         if (xp == start_plot) {
  2466.         /* Simply nip off the first element of the list. */
  2467.             new_list = first_plot = yp;
  2468.             xp = xp->next_cp;
  2469.             if (yp->next_cp != NULL)
  2470.                 yp = yp->next_cp;
  2471.         /* Add start_plot to the free_list. */
  2472.             if (free_head == NULL) {
  2473.                 free_list = free_head = start_plot;
  2474.                 free_head->next_cp = NULL;
  2475.             } else {
  2476.                 free_list->next_cp = start_plot;
  2477.                 start_plot->next_cp = NULL;
  2478.                 free_list = start_plot;
  2479.             }
  2480.         }
  2481.         else {
  2482.         /* Here, remove the xp node and replace it with the yp node. */
  2483.             tmp = xp;
  2484.         /* Pass over any data files that might have been in place. */
  2485.             while (new_list->next_cp && new_list->next_cp != xp) 
  2486.                 new_list = new_list->next_cp;
  2487.             new_list->next_cp = yp;
  2488.             new_list = new_list->next_cp;
  2489.             xp = xp->next_cp;
  2490.             if (yp->next_cp != NULL)
  2491.                 yp = yp->next_cp;
  2492.         /* Add tmp to the free_list. */
  2493.             tmp->next_cp = NULL;
  2494.             if (free_head == NULL) {
  2495.                 free_list = free_head = tmp;
  2496.             } else {
  2497.                 free_list->next_cp = tmp;
  2498.                 free_list = tmp;
  2499.             }
  2500.         }
  2501.     }
  2502. /* Ok, stick the free list at the end of the curve_points plot list. */
  2503.     while (new_list->next_cp != NULL)
  2504.         new_list = new_list->next_cp;
  2505.     new_list->next_cp = free_head;
  2506.  
  2507. /* Report the overall graph mins and maxs. */
  2508.     *x_min = lxmin;
  2509.     *x_max = lxmax;
  2510. }
  2511.  
  2512. void parametric_3dfixup(start_plot, plot_num, x_min, x_max, y_min, y_max,
  2513.                                 z_min, z_max)
  2514. struct surface_points *start_plot;
  2515. int *plot_num;
  2516. double *x_min, *x_max, *y_min, *y_max, *z_min, *z_max;
  2517. /*
  2518.     The hardest part of this routine is collapsing the FUNC plot types
  2519.    in the list (which are gauranteed to occur in (x,y,z) triplets while 
  2520.     preserving the non-FUNC type plots intact.  This means we have to
  2521.     work our way through various lists.  Examples (hand checked):
  2522.         start_plot:F1->F2->F3->NULL ==> F3->NULL
  2523.         start_plot:F1->F2->F3->F4->F5->F6->NULL ==> F3->F6->NULL
  2524.         start_plot:F1->F2->F3->D1->D2->F4->F5->F6->D3->NULL ==>
  2525.                         F3->D1->D2->F6->D3->NULL
  2526. */
  2527. {
  2528.     struct surface_points *xp, *yp, *zp, *new_list, *tmp, 
  2529.             *free_list, *free_head=NULL;
  2530.     struct iso_curve *icrvs, *xicrvs, *yicrvs, *zicrvs;
  2531.     int i, tlen, surface;
  2532.     char *new_title;
  2533.     double lxmin, lxmax, lymin, lymax, lzmin, lzmax, temp;
  2534.  
  2535.     if (autoscale_lx) {
  2536.         lxmin = VERYLARGE;
  2537.         lxmax = -VERYLARGE;
  2538.     } else {
  2539.         lxmin = xmin;
  2540.         lxmax = xmax;
  2541.     }
  2542.  
  2543.     if (autoscale_ly) {
  2544.         lymin = VERYLARGE;
  2545.         lymax = -VERYLARGE;
  2546.     } else {
  2547.         lymin = ymin;
  2548.         lymax = ymax;
  2549.     }
  2550.  
  2551.     if (autoscale_lz) {
  2552.         lzmin = VERYLARGE;
  2553.         lzmax = -VERYLARGE;
  2554.     } else {
  2555.         lzmin = zmin;
  2556.         lzmax = zmax;
  2557.     }
  2558.  
  2559. /* 
  2560.     Ok, go through all the plots and move FUNC3D types together.  Note:
  2561.     this originally was written to look for a NULL next pointer, but
  2562.     gnuplot wants to be sticky in grabbing memory and the right number
  2563.     of items in the plot list is controlled by the plot_num variable.
  2564.  
  2565.     Since gnuplot wants to do this sticky business, a free_list of 
  2566.     surface_points is kept and then tagged onto the end of the plot list as
  2567.     this seems more in the spirit of the original memory behavior than
  2568.     simply freeing the memory.  I'm personally not convinced this sort
  2569.     of concern is worth it since the time spent computing points seems
  2570.     to dominate any garbage collecting that might be saved here...
  2571. */
  2572.     new_list = xp = start_plot; 
  2573.     for (surface = 0; surface < *plot_num; surface++) {
  2574.         if (xp->plot_type != FUNC3D) {
  2575.             icrvs = xp->iso_crvs;
  2576.  
  2577.             while ( icrvs ) {
  2578.                 struct coordinate *points = icrvs->points;
  2579.  
  2580.                 for (i = 0; i < icrvs->p_count; ++i) {
  2581.                     if (lxmin > points[i].x)
  2582.                         lxmin = points[i].x;
  2583.                     if (lxmax < points[i].x)
  2584.                         lxmax = points[i].x;
  2585.                     if (lymin > points[i].y)
  2586.                         lymin = points[i].y;
  2587.                     if (lymax < points[i].y)
  2588.                         lymax = points[i].y;
  2589.                     if (lzmin > points[i].z)
  2590.                         lzmin = points[i].z;
  2591.                     if (lzmax < points[i].z)
  2592.                         lzmax = points[i].z;
  2593.                 }
  2594.  
  2595.                 icrvs = icrvs->next;
  2596.             }
  2597.             xp = xp->next_sp;
  2598.             continue;
  2599.         }
  2600.  
  2601.         yp = xp->next_sp;
  2602.         zp = yp->next_sp;
  2603.  
  2604.     /* Here's a FUNC3D parametric function defined as three parts. */
  2605.         (*plot_num) -= 2;
  2606.     /* 
  2607.         Go through all the points and assign the x's and y's from xp
  2608.         and yp to zp.  Check max's and min's as you go.
  2609.     */
  2610.         xicrvs = xp->iso_crvs;
  2611.         yicrvs = yp->iso_crvs;
  2612.         zicrvs = zp->iso_crvs;
  2613.         while ( zicrvs ) {
  2614.             struct coordinate *xpoints = xicrvs->points,
  2615.                      *ypoints = yicrvs->points,
  2616.                      *zpoints = zicrvs->points;
  2617.             for (i = 0; i < zicrvs->p_count; ++i) {
  2618.                 zpoints[i].x = xpoints[i].z;
  2619.                 zpoints[i].y = ypoints[i].z;
  2620.  
  2621.                 if (lxmin > zpoints[i].x) lxmin = zpoints[i].x;
  2622.                 if (lxmax < zpoints[i].x) lxmax = zpoints[i].x;
  2623.                 if (lymin > zpoints[i].y) lymin = zpoints[i].y;
  2624.                 if (lymax < zpoints[i].y) lymax = zpoints[i].y;
  2625.                 if (lzmin > zpoints[i].z) lzmin = zpoints[i].z;
  2626.                 if (lzmax < zpoints[i].z) lzmax = zpoints[i].z;
  2627.             }
  2628.             xicrvs = xicrvs->next;
  2629.             yicrvs = yicrvs->next;
  2630.             zicrvs = zicrvs->next;
  2631.         }
  2632.  
  2633.     /* Ok, fix up the title to include xp and yp plots. */
  2634.         if ((xp->title && xp->title[0] != '\0') ||
  2635.             (yp->title && yp->title[0] != '\0')) {
  2636.             tlen = (xp->title ? strlen(xp->title) : 0) +
  2637.                    (yp->title ? strlen(yp->title) : 0) +
  2638.                    (zp->title ? strlen(zp->title) : 0) + 5;
  2639.             new_title = alloc ((unsigned int) tlen, "string");
  2640.             new_title[0] = 0;
  2641.             if (xp->title) {
  2642.                 strcat(new_title, xp->title);
  2643.                 strcat(new_title, ", ");       /* + 2 */
  2644.             }
  2645.             if (yp->title) {
  2646.                 strcat(new_title, yp->title);
  2647.                 strcat(new_title, ", ");       /* + 2 */
  2648.             }
  2649.             if (zp->title) {
  2650.                 strcat(new_title, zp->title);
  2651.             }
  2652.             free (zp->title);
  2653.             zp->title = new_title;
  2654.         }
  2655.  
  2656.     /* Eliminate the first two surfaces (xp and yp) and just use the third. */
  2657.         if (xp == start_plot) {
  2658.         /* Simply nip off the first two elements of the list. */
  2659.             new_list = first_3dplot = zp;
  2660.             xp = zp->next_sp;
  2661.         /* Add xp and yp to the free_list. */
  2662.             if (free_head == NULL) {
  2663.                 free_head = start_plot;
  2664.             } else {
  2665.                 free_list->next_sp = start_plot;
  2666.             }
  2667.             free_list = start_plot->next_sp;
  2668.             free_list->next_sp = NULL;
  2669.         }
  2670.         else {
  2671.         /* Here, remove the xp,yp nodes and replace them with the zp node. */
  2672.             tmp = xp;
  2673.         /* Pass over any data files that might have been in place. */
  2674.             while (new_list->next_sp && new_list->next_sp != xp)
  2675.                 new_list = new_list->next_sp;
  2676.             new_list->next_sp = zp;
  2677.             new_list = zp;
  2678.             xp = zp->next_sp;
  2679.         /* Add tmp to the free_list. */
  2680.             if (free_head == NULL) {
  2681.                 free_head = tmp;
  2682.             } else {
  2683.                 free_list->next_sp = tmp;
  2684.             }
  2685.             free_list = tmp->next_sp;
  2686.             free_list->next_sp = NULL;
  2687.         }
  2688.     }
  2689. /* Ok, stick the free list at the end of the surface_points plot list. */
  2690.     while (new_list->next_sp != NULL)
  2691.         new_list = new_list->next_sp;
  2692.     new_list->next_sp = free_head;
  2693.       if (lxmax - lxmin < zero) {
  2694.           if (fabs(lxmax) < zero) {
  2695.               lxmin = -1.0;
  2696.               lxmax = 1.0;
  2697.           }
  2698.           else {
  2699.               lxmin *= 0.9;
  2700.               lxmax *= 1.1;
  2701.           }
  2702.       }
  2703.       if (lymax - lymin < zero) {
  2704.           if (fabs(lymax) < zero) {
  2705.               lymin = -1.0;
  2706.               lymax = 1.0;
  2707.           }
  2708.           else {
  2709.               lymin *= 0.9;
  2710.               lymax *= 1.1;
  2711.           }
  2712.       }
  2713.       if (lzmax - lzmin < zero) {
  2714.           if (fabs(lzmax) < zero) {
  2715.               lzmin = -1.0;
  2716.               lzmax = 1.0;
  2717.           }
  2718.           else {
  2719.               lzmin *= 0.9;
  2720.               lzmax *= 1.1;
  2721.           }
  2722.       }
  2723.  
  2724. /* Report the overall graph mins and maxs. */
  2725.     if (autoscale_lx) {
  2726.         *x_min = (log_x ? pow(10.0, lxmin) : lxmin);
  2727.         *x_max = (log_x ? pow(10.0, lxmax) : lxmax);
  2728.     }
  2729.     else {
  2730.         *x_min = xmin;
  2731.         *x_max = xmax;
  2732.     }
  2733.     if (autoscale_ly) {
  2734.         *y_min = (log_y ? pow(10.0, lymin) : lymin);
  2735.         *y_max = (log_y ? pow(10.0, lymax) : lymax);
  2736.     }
  2737.     else {
  2738.         *y_min = ymin;
  2739.         *y_max = ymax;
  2740.     }
  2741.     if (autoscale_lz) {
  2742.         *z_min = (log_z ? pow(10.0, lzmin) : lzmin);
  2743.         *z_max = (log_z ? pow(10.0, lzmax) : lzmax);
  2744.     }
  2745.     else {
  2746.         *z_min = zmin;
  2747.         *z_max = zmax;
  2748.     }
  2749. }
  2750.  
  2751. #ifdef AMIGA_LC_5_1
  2752. void sleep(delay)
  2753. unsigned int delay;
  2754. {
  2755.   Delay(50 * delay);
  2756. }
  2757. #endif
  2758.  
  2759. #ifdef AMIGA_AC_5
  2760. void sleep(delay)
  2761. unsigned int delay;
  2762. {
  2763. unsigned long time_is_up;
  2764.     time_is_up = time(NULL) + (unsigned long) delay; 
  2765.     while (time(NULL)<time_is_up)
  2766.         /* wait */ ;
  2767. }
  2768. #endif
  2769.  
  2770. #ifdef MSDOS
  2771. #ifndef __TURBOC__    /* Turbo C already has sleep() */
  2772. #ifndef __ZTC__     /* ZTC already has usleep() */
  2773. /* kludge to provide sleep() for msc 5.1 */
  2774. void sleep(delay)
  2775. unsigned int delay;
  2776. {
  2777. unsigned long time_is_up;
  2778.     time_is_up = time(NULL) + (unsigned long) delay; 
  2779.     while (time(NULL)<time_is_up)
  2780.         /* wait */ ;
  2781. }
  2782. #endif /* not ZTC */
  2783. #endif /* not TURBOC */
  2784. #endif /* MSDOS */
  2785.  
  2786.  
  2787. /* Support for input, shell, and help for various systems */
  2788.  
  2789. #ifdef vms
  2790.  
  2791. #include <descrip.h>
  2792. #include <rmsdef.h>
  2793. #include <errno.h>
  2794. #include <smgdef.h>
  2795. #include <smgmsg.h>
  2796.  
  2797. extern lib$get_input(), lib$put_output();
  2798. extern smg$read_composed_line();
  2799.  
  2800. int vms_len;
  2801.  
  2802. unsigned int status[2] = {1, 0};
  2803.  
  2804. static char help[MAX_LINE_LEN+1] = "gnuplot";
  2805.  
  2806. $DESCRIPTOR(prompt_desc,PROMPT);
  2807. $DESCRIPTOR(line_desc,input_line);
  2808.  
  2809. $DESCRIPTOR(help_desc,help);
  2810. $DESCRIPTOR(helpfile_desc,"GNUPLOT$HELP");
  2811.  
  2812.  
  2813. read_line(prompt)
  2814. char *prompt;
  2815. {
  2816.     int more, start=0;
  2817.     char expand_prompt[40];
  2818.  
  2819.     prompt_desc.dsc$w_length = strlen (prompt);
  2820.     prompt_desc.dsc$a_pointer = prompt;
  2821.     (void) strcpy (expand_prompt, "_");
  2822.     (void) strncat (expand_prompt, prompt, 38);
  2823.     do {
  2824.         line_desc.dsc$w_length = MAX_LINE_LEN - start;
  2825.         line_desc.dsc$a_pointer = &input_line[start];
  2826.         switch(status[1] = smg$read_composed_line(&vms_vkid,0,&line_desc, &prompt_desc, &vms_len)){
  2827.           case SMG$_EOF:
  2828.           done(IO_SUCCESS);    /* ^Z isn't really an error */
  2829.           break;
  2830.           case RMS$_TNS:    /* didn't press return in time *
  2831.                            /
  2832.                            vms_len--; /* skip the last character */
  2833.           break;            /* and parse anyway */
  2834.           case RMS$_BES:    /* Bad Escape Sequence */
  2835.           case RMS$_PES:    /* Partial Escape Sequence */
  2836.           sys$putmsg(status);
  2837.           vms_len = 0;        /* ignore the line */
  2838.           break;
  2839.           case SS$_NORMAL:
  2840.           break;            /* everything's fine */
  2841.           default:
  2842.           done(status[1]);    /* give the error message */
  2843.         }
  2844.         start += vms_len;
  2845.         input_line[start] = '\0';
  2846.        inline_num++;
  2847.         if (input_line[start-1] == '\\') {
  2848.           /* Allow for a continuation line. */
  2849.           prompt_desc.dsc$w_length = strlen (expand_prompt);
  2850.           prompt_desc.dsc$a_pointer = expand_prompt;
  2851.           more = 1;
  2852.           --start;
  2853.         }
  2854.         else {
  2855.           line_desc.dsc$w_length = strlen(input_line);
  2856.           line_desc.dsc$a_pointer = input_line;
  2857.           more = 0;
  2858.         }
  2859.     } while (more);
  2860. }
  2861.  
  2862.  
  2863. do_help()
  2864. {
  2865.     help_desc.dsc$w_length = strlen(help);
  2866.     if ((vaxc$errno = lbr$output_help(lib$put_output,0,&help_desc,
  2867.         &helpfile_desc,0,lib$get_input)) != SS$_NORMAL)
  2868.             os_error("can't open GNUPLOT$HELP",NO_CARET);
  2869. }
  2870.  
  2871.  
  2872. do_shell()
  2873. {
  2874.     if ((vaxc$errno = lib$spawn()) != SS$_NORMAL) {
  2875.         os_error("spawn error",NO_CARET);
  2876.     }
  2877. }
  2878.  
  2879.  
  2880. do_system()
  2881. {
  2882.     input_line[0] = ' ';    /* an embarrassment, but... */
  2883.  
  2884.     if ((vaxc$errno = lib$spawn(&line_desc)) != SS$_NORMAL)
  2885.         os_error("spawn error",NO_CARET);
  2886.  
  2887.     (void) putc('\n',stderr);
  2888. }
  2889.  
  2890. #else /* vms */
  2891.  
  2892. /* do_help: (not VMS, although it would work)
  2893.  * Give help to the user. 
  2894.  * It parses the command line into helpbuf and supplies help for that 
  2895.  * string. Then, if there are subtopics available for that key,
  2896.  * it prompts the user with this string. If more input is
  2897.  * given, do_help is called recursively, with the argument the index of 
  2898.  * null character in the string. Thus a more specific help can be 
  2899.  * supplied. This can be done repeatedly. 
  2900.  * If null input is given, the function returns, effecting a
  2901.  * backward climb up the tree.
  2902.  * David Kotz (David.Kotz@Dartmouth.edu) 10/89
  2903.  */
  2904. do_help()
  2905. {
  2906.     static char *helpbuf = NULL;
  2907.     static char *prompt = NULL;
  2908.     int base;                /* index of first char AFTER help string */
  2909.     int len;                /* length of current help string */
  2910.     BOOLEAN more_help;
  2911.     BOOLEAN only;            /* TRUE if only printing subtopics */
  2912.     int subtopics;            /* 0 if no subtopics for this topic */
  2913.     int start;                /* starting token of help string */
  2914.     char *help_ptr;            /* name of help file */
  2915.  
  2916.     if ( (help_ptr = getenv("GNUHELP")) == (char *)NULL )
  2917.         /* if can't find environment variable then just use HELPFILE */
  2918.         help_ptr = HELPFILE;
  2919.  
  2920.     /* Since MSDOS DGROUP segment is being overflowed we can not allow such  */
  2921.     /* huge static variables (1k each). Instead we dynamically allocate them */
  2922.     /* on the first call to this function...                     */
  2923.     if (helpbuf == NULL) {
  2924.     helpbuf = alloc(MAX_LINE_LEN, "help buffer");
  2925.     prompt = alloc(MAX_LINE_LEN, "help prompt");
  2926.     helpbuf[0] = prompt[0] = 0;
  2927.     }
  2928.  
  2929.     len = base = strlen(helpbuf);
  2930.  
  2931.     /* find the end of the help command */
  2932.     for (start = c_token; !(END_OF_COMMAND); c_token++)
  2933.      ;
  2934.     /* copy new help input into helpbuf */
  2935.     if (len > 0)
  2936.      helpbuf[len++] = ' ';    /* add a space */
  2937.     capture(helpbuf+len, start, c_token-1);
  2938.     squash_spaces(helpbuf+base); /* only bother with new stuff */
  2939.     lower_case(helpbuf+base); /* only bother with new stuff */
  2940.     len = strlen(helpbuf);
  2941.  
  2942.     /* now, a lone ? will print subtopics only */
  2943.     if (strcmp(helpbuf + (base ? base+1 : 0), "?") == 0) {
  2944.        /* subtopics only */
  2945.        subtopics = 1;
  2946.        only = TRUE;
  2947.        helpbuf[base] = '\0';    /* cut off question mark */
  2948.     } else {
  2949.        /* normal help request */
  2950.        subtopics = 0;
  2951.        only = FALSE;
  2952.     }
  2953.  
  2954.     switch (help(helpbuf, help_ptr, &subtopics)) {
  2955.        case H_FOUND: {
  2956.           /* already printed the help info */
  2957.           /* subtopics now is true if there were any subtopics */
  2958.           screen_ok = FALSE;
  2959.     
  2960.           do {
  2961.              if (subtopics && !only) {
  2962.                 /* prompt for subtopic with current help string */
  2963.                 if (len > 0)
  2964.                   (void) sprintf(prompt, "Subtopic of %s: ", helpbuf);
  2965.                 else
  2966.                   (void) strcpy(prompt, "Help topic: ");
  2967.                 read_line(prompt);
  2968.                 num_tokens = scanner(input_line);
  2969.                 c_token = 0;
  2970.                 more_help = !(END_OF_COMMAND);
  2971.                 if (more_help)
  2972.                   /* base for next level is all of current helpbuf */
  2973.                   do_help();
  2974.              } else 
  2975.                more_help = FALSE;
  2976.           } while(more_help);
  2977.     
  2978.           break;
  2979.        }
  2980.        case H_NOTFOUND: {
  2981.           printf("Sorry, no help for '%s'\n", helpbuf);
  2982.           break;
  2983.        }
  2984.        case H_ERROR: {
  2985.           perror(help_ptr);
  2986.           break;
  2987.        }
  2988.        default: {        /* defensive programming */
  2989.           int_error("Impossible case in switch\n", NO_CARET);
  2990.           /* NOTREACHED */
  2991.        }
  2992.     }
  2993.     
  2994.     helpbuf[base] = '\0';    /* cut it off where we started */
  2995. }
  2996.  
  2997. #ifdef AMIGA_AC_5
  2998. char strg0[256];
  2999. #endif
  3000.  
  3001. do_system()
  3002. {
  3003. #ifdef AMIGA_AC_5
  3004.    char *parms[80];
  3005.    void getparms();
  3006.  
  3007.    getparms(input_line+1,parms);
  3008.    if(fexecv(parms[0],parms) < 0)
  3009. #else
  3010.    if (system(input_line + 1))
  3011. #endif /* AMIGA_AC_5 */
  3012.       os_error("system() failed",NO_CARET);
  3013. }
  3014.  
  3015. #ifdef AMIGA_AC_5
  3016.  
  3017. /******************************************************************************/
  3018. /*                                                                            */
  3019. /*  Parses the command string (for fexecv use) and  converts the first token  */
  3020. /*     to lower case                                                          */
  3021. /*                                                                            */
  3022. /******************************************************************************/
  3023.  
  3024. void getparms(command,parms)
  3025.    char *command;
  3026.    char **parms;
  3027.    {
  3028.    register int i = 0;                         /* A bunch of indices          */
  3029.    register int j = 0;
  3030.    register int k = 0;
  3031.  
  3032.    while(*(command+j) != '\0')                 /* Loop on string characters   */
  3033.       {
  3034.       parms[k++] = strg0+i;
  3035.       while(*(command+j) == ' ') ++j;
  3036.       while(*(command+j) != ' ' && *(command+j) != '\0')
  3037.          {
  3038.          if(*(command+j) == '"')               /* Get quoted string           */
  3039.             for(*(strg0+(i++)) = *(command+(j++));
  3040.                 *(command+j)  != '"';
  3041.                 *(strg0+(i++)) = *(command+(j++)));
  3042.          *(strg0+(i++)) = *(command+(j++));
  3043.          }
  3044.       *(strg0+(i++)) = '\0';                   /* NUL terminate every token   */
  3045.       }
  3046.    parms[k] = '\0';
  3047.  
  3048.    for(k=strlen(strg0)-1; k>=0; --k)           /* Convert to lower case       */
  3049.       *(strg0+k)>='A' && *(strg0+k)<='Z'? *(strg0+k)|=32: *(strg0+k);
  3050.    }
  3051.  
  3052. #endif /* AMIGA_AC_5 */
  3053.  
  3054. #ifdef READLINE
  3055. char *
  3056. rlgets(s, n, prompt)
  3057. char *s;
  3058. int n;
  3059. char *prompt;
  3060. {
  3061.       char *readline();
  3062.       static char *line = (char *)NULL;
  3063.  
  3064.       /* If we already have a line, first free it */
  3065.       if(line != (char *)NULL) 
  3066.               free(line);
  3067.  
  3068.       line = readline((interactive)?prompt:"");
  3069.  
  3070.       /* If it's not an EOF */
  3071.       if(line) {
  3072.       if (*line)
  3073.               add_history(line);
  3074.       strncpy(s, line, n);
  3075.       return s;
  3076.       }
  3077.  
  3078.       return line;
  3079. }
  3080. #endif /* READLINE */
  3081.  
  3082. #ifdef MSDOS
  3083.  
  3084. #ifdef __TURBOC__
  3085. /* cgets implemented using dos functions */
  3086. /* Maurice Castro 22/5/91 */
  3087. char *doscgets(s)
  3088. char *s;
  3089. {
  3090.    long datseg;
  3091.  
  3092.    /* protect and preserve segments - call dos to do the dirty work */
  3093.    datseg = _DS;
  3094.  
  3095.    _DX = FP_OFF(s);
  3096.    _DS = FP_SEG(s);
  3097.    _AH = 0x0A;
  3098.    geninterrupt(33);
  3099.    _DS = datseg;
  3100.  
  3101.    /* check for a carriage return and then clobber it with a null */
  3102.    if (s[s[1]+2] == '\r') 
  3103.       s[s[1]+2] = 0;
  3104.  
  3105.    /* return the input string */
  3106.    return(&(s[2]));
  3107.    }
  3108. #endif /* __TURBOC__ */
  3109.  
  3110.  
  3111. read_line(prompt)
  3112.     char *prompt;
  3113. {
  3114.     register int i;
  3115.     int start = 0, ilen = 0;
  3116.     BOOLEAN more;
  3117.     int last;
  3118.     char *p, *crnt_prompt = prompt;
  3119.     
  3120. #ifndef __ZTC__
  3121.     if (interactive) { /* if interactive use console IO so CED will work */
  3122. #ifndef READLINE
  3123.         cputs(prompt);
  3124. #endif /* READLINE */
  3125.         do {
  3126.            ilen = MAX_LINE_LEN-start-1;
  3127.            input_line[start] = ilen > 126 ? 126 : ilen;
  3128. #ifdef READLINE
  3129.            input_line[start+2] = 0;
  3130.            (void) rlgets(&(input_line[start+2]), ilen, crnt_prompt );
  3131.            if (p = strchr(&(input_line[start+2]), '\r')) *p = 0;
  3132.            if (p = strchr(&(input_line[start+2]), '\n')) *p = 0;
  3133.            input_line[start+1] = strlen(&(input_line[start+2]));
  3134. #else /* READLINE */
  3135. #ifdef __TURBOC__
  3136.            (void) doscgets(&(input_line[start]));
  3137. #else /* __TURBOC__ */
  3138.            (void) cgets(&(input_line[start]));
  3139. #endif /* __TURBOC__ */
  3140.            (void) putc('\n',stderr);
  3141. #endif /* READLINE */
  3142.            if (input_line[start+2] == 26) {
  3143.               /* end-of-file */
  3144.               (void) putc('\n',stderr);
  3145.               input_line[start] = '\0';
  3146.               inline_num++;
  3147.               if (start > 0)    /* don't quit yet - process what we have */
  3148.                 more = FALSE;
  3149.               else {
  3150.                  (void) putc('\n',stderr);
  3151.                  done(IO_SUCCESS);
  3152.                  /* NOTREACHED */
  3153.               }
  3154.            } else {
  3155.               /* normal line input */
  3156.               register i = start;
  3157.               while ( (input_line[i] = input_line[i+2]) != (char)NULL )
  3158.                 i++;        /* yuck!  move everything down two characters */
  3159.  
  3160.               inline_num++;
  3161.               last = strlen(input_line) - 1;
  3162.               if (last + 1 >= MAX_LINE_LEN)
  3163.                 int_error("Input line too long",NO_CARET);
  3164.                      
  3165.               if (input_line[last] == '\\') { /* line continuation */
  3166.                  start = last;
  3167.                  more = TRUE;
  3168.               } else
  3169.                 more = FALSE;
  3170.            }
  3171. #ifndef READLINE
  3172.            if (more)
  3173.             cputs("> ");
  3174. #else
  3175.            crnt_prompt = "> ";
  3176. #endif /* READLINE */
  3177.         } while(more);
  3178.     }
  3179.     else { /* not interactive */
  3180. #endif /* not ZTC */
  3181.         if (interactive)
  3182.          fputs(prompt,stderr);
  3183.         do {
  3184.            /* grab some input */
  3185.            if ( fgets(&(input_line[start]), MAX_LINE_LEN - start, stdin) 
  3186.                     == (char *)NULL ) {
  3187.               /* end-of-file */
  3188.               if (interactive)
  3189.                 (void) putc('\n',stderr);
  3190.               input_line[start] = '\0';
  3191.               inline_num++;
  3192.               if (start > 0)    /* don't quit yet - process what we have */
  3193.                 more = FALSE;
  3194.               else
  3195.                 done(IO_SUCCESS); /* no return */
  3196.            } else {
  3197.               /* normal line input */
  3198.               last = strlen(input_line) - 1;
  3199.               if (input_line[last] == '\n') { /* remove any newline */
  3200.                  input_line[last] = '\0';
  3201.                  /* Watch out that we don't backup beyond 0 (1-1-1) */
  3202.                  if (last > 0) --last;
  3203.                  inline_num++;
  3204.               } else if (last+1 >= MAX_LINE_LEN)
  3205.                 int_error("Input line too long",NO_CARET);
  3206.                      
  3207.               if (input_line[last] == '\\') { /* line continuation */
  3208.                  start = last;
  3209.                  more = TRUE;
  3210.               } else
  3211.                 more = FALSE;
  3212.            }
  3213.             if (more && interactive)
  3214.             fputs("> ", stderr);
  3215.         } while(more);
  3216. #ifndef __ZTC__
  3217.     }
  3218. #endif
  3219. }
  3220.  
  3221.  
  3222. do_shell()
  3223. {
  3224. register char *comspec;
  3225.     if ((comspec = getenv("COMSPEC")) == (char *)NULL)
  3226.         comspec = "\command.com";
  3227.     if (spawnl(P_WAIT,comspec,NULL) == -1)
  3228.         os_error("unable to spawn shell",NO_CARET);
  3229. }
  3230.  
  3231. #else /* MSDOS */
  3232.         /* plain old Unix */
  3233.  
  3234. read_line(prompt)
  3235.     char *prompt;
  3236. {
  3237.     int start = 0;
  3238.     BOOLEAN more = FALSE;
  3239.     int last = 0;
  3240.  
  3241. #ifndef READLINE
  3242.     if (interactive)
  3243.      fputs(prompt,stderr);
  3244. #endif /* READLINE */
  3245.     do {
  3246.        /* grab some input */
  3247. #ifdef READLINE
  3248.      if (((interactive)
  3249.          ?rlgets(&(input_line[start]), MAX_LINE_LEN - start,
  3250.                 ((more)?"> ":prompt))
  3251.          :fgets(&(input_line[start]), MAX_LINE_LEN - start, stdin))
  3252.                               == (char *)NULL ) {
  3253. #else
  3254.        if ( fgets(&(input_line[start]), MAX_LINE_LEN - start, stdin) 
  3255.                 == (char *)NULL ) {
  3256. #endif /* READLINE */
  3257.           /* end-of-file */
  3258.           if (interactive)
  3259.             (void) putc('\n',stderr);
  3260.           input_line[start] = '\0';
  3261.           inline_num++;
  3262.           if (start > 0)    /* don't quit yet - process what we have */
  3263.             more = FALSE;
  3264.           else
  3265.             done(IO_SUCCESS); /* no return */
  3266.        } else {
  3267.           /* normal line input */
  3268.           last = strlen(input_line) - 1;
  3269.           if (input_line[last] == '\n') { /* remove any newline */
  3270.              input_line[last] = '\0';
  3271.                 /* Watch out that we don't backup beyond 0 (1-1-1) */
  3272.              if (last > 0) --last;
  3273.              inline_num++;
  3274.           } else if (last+1 >= MAX_LINE_LEN)
  3275.             int_error("Input line too long",NO_CARET);
  3276.                  
  3277.           if (input_line[last] == '\\') { /* line continuation */
  3278.              start = last;
  3279.              more = TRUE;
  3280.           } else
  3281.             more = FALSE;
  3282.        }
  3283. #ifndef READLINE
  3284.         if (more && interactive)
  3285.         fputs("> ", stderr);
  3286. #endif
  3287.     } while(more);
  3288. }
  3289.  
  3290. #ifdef VFORK
  3291.  
  3292. do_shell()
  3293. {
  3294. register char *shell;
  3295. register int p;
  3296. static int execstat;
  3297.     if (!(shell = getenv("SHELL")))
  3298.         shell = SHELL;
  3299. #ifdef AMIGA_AC_5
  3300.     execstat = fexecl(shell,shell,NULL);
  3301. #else
  3302.     if ((p = vfork()) == 0) {
  3303.         execstat = execl(shell,shell,NULL);
  3304.         _exit(1);
  3305.     } else if (p == -1)
  3306.         os_error("vfork failed",c_token);
  3307.     else
  3308.         while (wait(NULL) != p)
  3309. #endif
  3310.             ;
  3311.     if (execstat == -1)
  3312.         os_error("shell exec failed",c_token);
  3313.     (void) putc('\n',stderr);
  3314. }
  3315. #else /* VFORK */
  3316.  
  3317. #ifdef AMIGA_LC_5_1
  3318. do_shell()
  3319. {
  3320. register char *shell;
  3321.     if (!(shell = getenv("SHELL")))
  3322.         shell = SHELL;
  3323.  
  3324.     if (system(shell))
  3325.         os_error("system() failed",NO_CARET);
  3326.  
  3327.     (void) putc('\n',stderr);
  3328. }
  3329. #else /* AMIGA_LC_5_1 */
  3330.  
  3331. #define EXEC "exec "
  3332. do_shell()
  3333. {
  3334. static char exec[100] = EXEC;
  3335. register char *shell;
  3336.     if (!(shell = getenv("SHELL")))
  3337.         shell = SHELL;
  3338.  
  3339.     if (system(strncpy(&exec[sizeof(EXEC)-1],shell,
  3340.         sizeof(exec)-sizeof(EXEC)-1)))
  3341.         os_error("system() failed",NO_CARET);
  3342.  
  3343.     (void) putc('\n',stderr);
  3344. }
  3345. #endif /* AMIGA_LC_5_1 */
  3346. #endif /* VFORK */
  3347. #endif /* MSDOS */
  3348. #endif /* vms */
  3349.